這篇文章給大家分享的是有關JavaScript對象的基礎知識點有哪些的內容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。
JavaScript有六種主要語言類型:
string , number , boolean ,undefined , null , object
基本類型:string,number,boolean,undefined,null;基本類型本身不是對象。
但是 null有時會被當成對象,typeof null 會返回object,實際上null是基本類型。原因是不同對象在底層都是表示為二進制,在JavaScript中二進制前三位都為0會被判斷為object類型,null表示全 0,所以typeof時會返回object。
數組也是對象的一種類型,具備一些額外的行為。數組的組織方式比一般的對象要復雜。
函數本質上和普通函數一樣,只是可以調用,所以可以操作對象一樣操作函數。
String
Number
Date
Boolean
Object
Function
Array
.a 稱之為屬性訪問,[‘a’]稱之為操作符訪問。
//對象中的屬性名始終是字符串
myobj={}
myobj[myobj]='bar'//賦值
myobj['[object object]'] //'bar'es6 增加可計算屬性名,可以在文字形式中使用 [] 包裹一個表達式來當作屬性名
var perfix = 'foo'
var myobj={
[perfix + 'bar'] :'hello'
}
myobj['foobar']//helloes5開始,所有屬性具備了屬性描述符,比如可以直接判斷屬性是否可讀可寫等。
/* * 重要函數: * Object.getOwnPropertyDescriptor(..) //獲取屬性描述符 * Object.defineProperty(..) //設置屬性描述符 */ writeble(可讀性) configurable(可配置性) enumerable (可枚舉性)
for in可用來遍歷對象的可枚舉屬性列表(包括[[Prototype]]鏈),需要手動獲取屬性值??梢员闅v數組及普通的對象
es6新增,可以用來遍歷數組的屬性值,for of循環首先會向被訪問對象請求一個迭代器對象,然后通過調用迭代器對象的next()方法來遍歷所有的返回值。
數組有內置的@@iterator,
var arr = [1, 2, 3]
var it = arr[Symbol.iterator]()//迭代器對象
console.log(it.next());//{value: 1, done: false}
console.log(it.next());//{value: 2, done: false}
console.log(it.next());//{value: 3, done: false}
console.log(it.next());//{value: undefined, done: true}
/*
* 用es6 的Symbol.iterator 來獲取對象的迭代器內部屬性。
* @@iterator本身并不是一個迭代器對象,而是一個返回迭代器對象的函數。
*/因為對象沒有內置一個@@iterator,無法自動完成for…of遍歷。但是,可以給你任何想遍歷的對象定義@@iterator,舉例來說:
var obj={
a:1,b:2
}
Object.defineProperty(obj, Symbol.iterator, {
enumerable: false,
writable: false,
configurable: true,
value: function () {
var self = this
var idx = 0
var ks = Object.keys(self)
return {
next: function () {
return {
value: self[ks[idx++]],
done: (idx > ks.length)
}
}
}
}
})
//手動遍歷
var it = obj[Symbol.iterator]()//迭代器對象
console.log(it.next());//{value: 1, done: false}
console.log(it.next());//{value: 2, done: false}
console.log(it.next());//{value: undefined, done: true}
//for of 遍歷
for (const v of obj) {
console.log(v);
}
//2
//3/* forEach:會遍歷所有并忽略返回值 some:會一直運行到回調函數返回 true(或者"真"值) every:會一直運行到回調函數返回 false(或者"假"值) map: filter:返回滿足條件的值 reduce: some和every 和for的break語句類似,會提前終止遍歷 */
上面提過,JavaScript的主要的語言類型有六種:string、number、boolean、null、undefined、object;其中前5種屬于基本類型,最后的object屬于引用類型。
棧:自動分配內存空間,系統自動釋放,里面存放的是基本類型的值和引用類型的地址
堆:動態分配的內存,大小不定,也不會自動釋放。里面存放引用類型的值
基本類型采用值傳遞;引用類型采用的地址(指針)傳遞,將存放在棧內存中的地址賦值給接收的 變量。
淺拷貝:對象的淺拷貝,會對‘主’對象進行拷貝,但不會復制對象里面的對象?!锩娴膶ο蟆瘯谠瓉淼膶ο蠛退母北局g共享。
深拷貝:對對象的深拷貝,不僅將原對象的各個屬性逐個復制出去,而且將原對象各個屬性所包含的對象也依次采用深復制的方法遞歸復制到新對象上,所以對一個對象的修改并不會影響另一個對象。
舉例來說:
var anotherObject={
b:"b"
}
var anotherArray=[]
var myObject={
a:'a',
b:anotherObject, //引用,不是副本
c:anotherArray //另外一個引用
}
anotherArray.push(anotherObject,myObject)
/*
如何準確的復制 myObject?
淺復制 myObject,就是復制出 新對象中的 a 的值會復制出對象中a 的值,也就是 'a',
但是對象中的 b、c兩個屬性其實只是三個引用,新對象的b、c屬性和舊對象的是一樣的。
深復制 myObject,除了復制 myObject 以外還會復制 anotherObject 和 anotherArray。
但是這里深復制 myObject會出現一個問題,anotherArray 引用 anotherObject 和 myObject,
所以又需要復制 myObject,這樣就會由于循環引用導致死循環。
后面會介紹如何處理這種情況。
*/object.assign()、擴展運算符(…)
var obj1 = {x: 1, y: 2}
var obj2 = Object.assign({}, obj1);
console.log(obj1) //{x: 1, y: 2}
console.log(obj2) //{x: 1, y: 2}
obj2.x = 2; //修改obj2.x
console.log(obj1) //{x: 1, y: 2}
console.log(obj2) //{x: 2, y: 2}
var obj1 = {
x: 1,
y: {
m: 1
}
};
var obj2 = Object.assign({}, obj1);
console.log(obj1) //{x: 1, y: {m: 1}}
console.log(obj2) //{x: 1, y: {m: 1}}
obj2.y.m = 2; //修改obj2.y.m
console.log(obj1) //{x: 1, y: {m: 2}}
console.log(obj2) //{x: 2, y: {m: 2}}slice()、concat、Array.from()、擴展運算符(…)、concat、for循環
var arr1 = [1, 2, [3, 4]], arr2 = arr1.slice(); console.log(arr1); //[1, 2, [3, 4]] console.log(arr2); //[1, 2, [3, 4]] arr2[0] = 2 arr2[2][1] = 5; console.log(arr1); //[1, 2, [3, 5]] console.log(arr2); //[2, 2, [3, 5]]
進行JSON.stringify()序列化的過程中,undefined、任意的函數以及 symbol 值,在序列化過程中會被忽略(出現在非數組對象的屬性值中時)或者被轉換成 null(出現在數組中時)。
var obj1 = {
x: 1,
y: {
m: 1
},
a:undefined,
b:function(a,b){
return a+b
},
c:Symbol("foo")
};
var obj2 = JSON.parse(JSON.stringify(obj1));
console.log(obj1) //{x: 1, y: {m: 1}, a: undefined, b: ?, c: Symbol(foo)}
console.log(obj2) //{x: 1, y: {m: 1}}
obj2.y.m = 2; //修改obj2.y.m
console.log(obj1) //{x: 1, y: {m: 1}, a: undefined, b: ?, c: Symbol(foo)}
console.log(obj2) //{x: 2, y: {m: 2}}function deepClone(obj){
let result = Array.isArray(obj)?[]:{};
if(obj && typeof obj === "object"){
for(let key in obj){
if(obj.hasOwnProperty(key)){
if(obj[key] && typeof obj[key] === "object"){
result[key] = deepClone(obj[key]);
}else{
result[key] = obj[key];
}
}
}
}
return result;
}
var obj1 = {
x: {
m: 1
},
y: undefined,
z: function add(z1, z2) {
return z1 + z2
},
a: Symbol("foo"),
b: [1,2,3,4,5],
c: null
};
var obj2 = deepClone(obj1);
obj2.x.m = 2;
obj2.b[0] = 2;
console.log(obj1);
console.log(obj2);
//obj1
{
a: Symbol(foo)
b: (5) [1, 2, 3, 4, 5]
c: null
x: {m: 1}
y: undefined
z: ? add(z1, z2)
}
//obj2
{
a: Symbol(foo)
b: (5) [2, 2, 3, 4, 5]
c: null
x: {m: 2}
y: undefined
z: ? add(z1, z2)
}上面的深拷貝方法遇到循環引用,會陷入一個循環的遞歸的過程,從而導致爆棧。因此需要改進。
解決因循環遞歸而暴棧的問題,只需要判斷一個對象的字段是否引用了這個對象或這個對象的任意父級即可。
function deepClone(obj, parent = null){ // 改進(1)
let result = Array.isArray(obj)?[]:{};
let _parent = parent; // 改進(2)
while(_parent){ // 改進(3)
if(_parent.originalParent === obj){
return _parent.currentParent;
}
_parent = _parent.parent;
}
if(obj && typeof obj === "object"){
for(let key in obj){
if(obj.hasOwnProperty(key)){
if(obj[key] && typeof obj[key] === "object"){
result[key] = deepClone(obj[key],{ // 改進(4)
originalParent: obj,
currentParent: result,
parent: parent
});
}else{
result[key] = obj[key];
}
}
}
}
return result;
}
// 調試用
var obj1 = {
x: 1,
y: 2
};
obj1.z = obj1;
var obj2 = deepClone(obj1);
console.log(obj1);
console.log(obj2);function deepClone(obj, parent = null){
let result; // 最后的返回結果
let _parent = parent; // 防止循環引用
while(_parent){
if(_parent.originalParent === obj){
return _parent.currentParent;
}
_parent = _parent.parent;
}
if(obj && typeof obj === "object"){ // 返回引用數據類型(null已被判斷條件排除))
if(obj instanceof RegExp){ // RegExp類型
result = new RegExp(obj.source, obj.flags)
}else if(obj instanceof Date){ // Date類型
result = new Date(obj.getTime());
}else{
if(obj instanceof Array){ // Array類型
result = []
}else{ // Object類型,繼承原型鏈
let proto = Object.getPrototypeOf(obj);
result = Object.create(proto);
}
for(let key in obj){ // Array類型 與 Object類型 的深拷貝
if(obj.hasOwnProperty(key)){
if(obj[key] && typeof obj[key] === "object"){
result[key] = deepClone(obj[key],{
originalParent: obj,
currentParent: result,
parent: parent
});
}else{
result[key] = obj[key];
}
}
}
}
}else{ // 返回基本數據類型與Function類型,因為Function不需要深拷貝
return obj
}
return result;
}
// 調試用
function construct(){
this.a = 1,
this.b = {
x:2,
y:3,
z:[4,5,[6]]
},
this.c = [7,8,[9,10]],
this.d = new Date(),
this.e = /abc/ig,
this.f = function(a,b){
return a+b
},
this.g = null,
this.h = undefined,
this.i = "hello",
this.j = Symbol("foo")
}
construct.prototype.str = "I'm prototype"
var obj1 = new construct()
obj1.k = obj1
obj2 = deepClone(obj1)
obj2.b.x = 999
obj2.c[0] = 666
console.log(obj1)
console.log(obj2)
console.log(obj1.str)
console.log(obj2.str)注:Function類型的深拷貝:
bind():使用fn.bind()可將函數進行深拷貝,但因為this指針指向問題而不能使用;
eval(fn.toString()):只支持箭頭函數,普通函數function fn(){}則不適用;
new Function(arg1,arg2,…,function_body):需將參數與函數體提取出來;
感謝各位的閱讀!關于“JavaScript對象的基礎知識點有哪些”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。