一、賦值
賦值是將某一數值或物件賦給某個變數的過程
- 基本資料型別:賦值,賦值之後兩個變數互不影響
- 引用資料型別:賦址,兩個變數具有相同的引用,指向同一個物件,相互之間有影響
對基本資料型別賦值操作,兩個變數互不影響
var a = 'Mike';
var b = a;
console.log(b);//Mike
a = "Lily";
console.log(a);//Lily
console.log(b);//Mike複製程式碼
對引用資料型別賦址操作,兩個變數指向同一個物件,改變a就會影響b
var a = {
name : 'Mike',
like : ['js','css']
}
var b = a;
console.log(b);
//{
// name:'Mike',
// like:['js',css]
//}
a.age = 17;
console.log(b);
//{
// name:'Mike',
// like:['js',css],
// age : 17
//}複製程式碼
通常在開發中並不希望改變變數a會影響到變數b,這時候就需要深拷貝和淺拷貝。
二、淺拷貝
1、什麼是淺拷貝
建立一個新物件,這個物件有著原始物件屬性值的一份精確拷貝。如果屬性是基本型別,拷貝的是基本型別值,如果是引用型別,拷貝的是記憶體地址,所以如果其中一個物件改變了地址,就會影響另一個物件
簡單來說,可以理解為淺拷貝只解決了第一層的問題
2、淺拷貝的使用場景
- Object.assign()
- 展開運算子
- Array.prototype.slice()
var a = {
name : 'Mike',
like : [
{
title:'js',
bookName:'高階程式設計'
},
{
title:'css',
bookName:'css世界'
},
]
};
var b = Object.assign({},a);
console.log(b);
//{
// name:'Mike',
// like:[
// {
// title:'js',
// bookName:'高階程式設計'
// },
// {
// title:'css',
// bookName:'css世界'
// }
// ]
//}
a.name = 'Lily';
a.like[0].title= 'html5';
a.like[0].bookName= 'html5程式設計';
console.log(b);
//{
// name:'Mike',
// like:[
// {
// title:'html5',
// bookName:'html5程式設計'
// },
// {
// title:'css',
// bookName:'css世界'
// }
// ]
//}
複製程式碼
上面程式碼說明改變a的name屬性值(基本型別)時,沒有影響到b的name屬性值,而當改變a的like屬性值(引用型別)時,b的like屬性值相應的發生變化。
展開運算子
var a = {
name : 'Mike',
like : [
{
title:'js',
bookName:'高階程式設計'
},
{
title:'css',
bookName:'css世界'
},
]
};
var b = {...a};
console.log(b);
//{
// name:'Mike',
// like:[
// {
// title:'js',
// bookName:'高階程式設計'
// },
// {
// title:'css',
// bookName:'css世界'
// }
// ]
//}
a.name = 'Lily';
a.like[0].title= 'html5';
a.like[0].bookName= 'html5程式設計';
console.log(b);
//{
// name:'Mike',
// like:[
// {
// title:'html5',
// bookName:'html5程式設計'
// },
// {
// title:'css',
// bookName:'css世界'
// }
// ]
//}複製程式碼
展開運算子和Object.assign()的實際效果一樣,只能拷貝第一層
Array.prototype.slice()
slice()方法返回一個新陣列物件,arr.slice([begin[, end]])
var a = [0,1,[3,4]];
var b = a.slice();
console.log(b);//[0,1,[3,4]]
a[2][0] = 5;
console.log(b);//[0,1,[5,4]]複製程式碼
當改變a[2][0]時,b也相應發生變化。
三、深拷貝
1、什麼是深拷貝
深拷貝會拷貝所有屬性,並拷貝屬性指向的動態分配記憶體。拷貝前後兩個物件互不影響。
2、深拷貝的使用場景
- JSON.parse(JSON.stringify(object))
- jQuery.extend()
- lodash.cloneDeep()
var a = {
name : 'Mike',
like : [
{
title:'js',
bookName:'高階程式設計'
},
{
title:'css',
bookName:'css世界'
},
]
};
var b = JSON.parse(JSON.stringify(a));
a.name = 'Lily';
a.like[0].title= 'html5';
a.like[0].bookName= 'html5程式設計';
console.log(b);
//{
// name:'Mike',
// like:[
// {
// title:'js',
// bookName:'高階程式設計'
// },
// {
// title:'css',
// bookName:'css世界'
// }
// ]
//}
console.log(a);
//{
// name:'Lily',
// like:[
// {
// title:'html5',
// bookName:'html5程式設計'
// },
// {
// title:'css',
// bookName:'css世界'
// }
// ]
//}
複製程式碼
var a = [0,1,[3,4]];
var b = JSON.parse(JSON.stringify(a));
a[2][0] = 5;
console.log(a);//[0,1,[5,4]]
console.log(b);//[0,1,[3,4]]複製程式碼
以上兩段程式碼說明,通過使用JSON.parse(JSON.stringify(object)),可以實現對陣列和物件的深拷貝。
但該方法有以下幾個問題:
1、會忽略undefined
2、會忽略symbol
3、不能序列化函式
4、不能處理正則
5、不能解決迴圈引用的物件
- 會忽略undefined 、會忽略symbol、不能序列化函式、不能處理正則
var obj = {
a:undefined,//undefined
b:Symbol('mike'),//Symbol()
c:function(){},//函式
e:/'123'/
};
var b = JSON.parse(JSON.stringify(obj));
console.log(obj);
//{
// a:undefined,
// b:Symbol('mike'),
// c:function(){},
// e:/'123'/
//}
console.log(b);
//{ e:{}}複製程式碼
- 迴圈引用情況下會報錯
var obj = {
a:1,
b:{
c:2
}
};
obj.a = obj.b;
obj.b.c = obj.a;
let b = JSON.parse(JSON.stringify(obj));
console.log(b);//VM288:13 Uncaught TypeError: Converting circular structure to JSON(…)複製程式碼
以上問題,和JSON有關。
四、如何實現深拷貝
function deep(source,hash = new WeakMap()){
//通過使用hash來解決迴圈引用的問題
if(hash.has(source)) return hash.get(source);
//判斷是物件還是陣列
var target = Array.isArray(source) ? [] : {};
hash.set(source,target);
for(var key in source){
//判斷是否是自身屬性,不是繼承屬性
if(Object.prototype.hasOwnProperty.call(source,key)){
//判斷屬性值是否是引用型別,如果是引用型別則遞迴繼續執行該函式
if(typeof source[key] === 'object' && source[key] !== null){
target[key] = deep(source[key],hash)
}else{
target[key] = source[key];
}
}
}
return target;
}複製程式碼