1. 是什麼
假設B複制了A,當修改A時,看B是否會發生變化:
如果B也跟着變了,說明這是淺拷貝。牆頭草,你變我也變。
如果B沒變,那就是深拷貝。
2. 産生的原因
JS存在基本類型和引用類型。
-
基本類型指的是簡單的資料段。我們複制他的時候,會建立新值,并把它放在一個新的變量的記憶體位址。
基本類型:Number Boolean String undefined null
複制:
js深淺拷貝 -
引用類型指的是一個對象,并且我們對對象的操作都隻是在操作它的引用而已。
引用類型:object,array,function,error,date
複制:
深淺拷貝是針對引用類型的。
3. 實作淺拷貝
3.1 array和object通用–循環複制
var shallowCopy = function(obj) {
// 判斷obj的類型是否是object類型
if (typeof obj !== 'object') return;
var newObj = obj instanceof Array ? [] : {};
// 周遊obj,并且判斷是obj的屬性才拷貝
for (var key in obj) {
// 不周遊原型鍊上的屬性,隻周遊自身屬性
if (obj.hasOwnProperty(key)) {
newObj[key] = obj[key];
}
}
return newObj;
}
var obj={
name:'123',
age:10,
}
var newObj=shallowCopy(obj);
obj.name='213';
console.log(newObj.name);
輸出:"123” 随之改變。
3.2 數組淺拷貝–slice()和contact()!!!
數組的資料類型是引用類型,在這種情況下是淺拷貝。
數組的資料類型是基本類型,在這種情況下是深拷貝。
淺拷貝:
var arr = [{old: 'old'}, ['old']];
var newArr1 = arr.concat();
var newArr2=arr.slice();
arr[0].old = 'new';
console.log(arr) // [{old: 'new'}, ['new']]
console.log(newArr1) // [{old: 'new'}, ['new']]
console.log(newArr2) // [{old: 'new'}, ['new']]
深拷貝:
var arr = ['old', 1, true, null, undefined];
var newArr1 = arr.concat();
var newArr2=arr.slice();
arr[0] = 'new';
console.log(arr) // [{old: 'new'}, ['new']]
console.log(newArr1) // [{old: 'old}, ['new']]
console.log(newArr2) // [{old: 'old'}, ['new']]
3.3 對象的淺拷貝–Object.assign !!!
這裡的Object.assign也是一個很奇怪的點,它既是深拷貝又是淺拷貝。一級屬性-深拷貝,深層屬性-淺拷貝
var obj = { a: 0 , b: { c: 0}};
var newObj = Object.assign({}, obj);
obj.a = 1;
obj.b.c = 3;
console.log(obj); // { a: 1 , b: { c: 3}};
console.log(newObj); // { a: 0 , b: { c: 3}};
可以很清楚的發現一級深拷貝,二級淺拷貝。
3.4 對象的淺拷貝-- 展開運算符(…)!!!
這裡的展開運算符(…)同樣是一個很奇怪的點,它既是深拷貝又是淺拷貝。一級屬性-深拷貝,深層屬性-淺拷貝
var obj = { a: 0 , b: { c: 0}};
var newObj = {...obj};
obj.a = 1;
obj.b.c = 3;
console.log(obj); // { a: 1 , b: { c: 3}};
console.log(newObj); // { a: 0 , b: { c: 3}};
可以很清楚的發現一級深拷貝,二級淺拷貝。
4. 深拷貝
在淺拷貝中已經介紹而來幾種深拷貝的方式。
4.1 JSON.parse(JSON.stringify())
數組和對象均可用
數組
var arr = [1, 3, {
name: ' syl'
}];
var newArr = JSON.parse(JSON.stringify(arr));
arr[2].name = '123';
console.log(newArr[2]); /// 'syl ' 沒有改變
對象
var obj={
name:'syl',
}
var newObj=JSON.parse(JSON.stringify(obj));
obj.name="123";
console.log(newObj.name); //'syl'. 沒有改變
這種方法雖然可以實作數組或對象深拷貝,但不能處理函數
var arr = [1, 3, {
name: ' syl'
},function(){}];
var newArr = JSON.parse(JSON.stringify(arr));
console.log(newArr[3]) // null ,沒有輸出函數。
這是因為JSON.stringify() 方法是将一個JavaScript值(對象或者數組)轉換為一個 JSON字元串,不能接受函數
4.2 深拷貝通用–遞歸
function deepCopy(obj) {
//是否是數組或對象
if (typeof obj !== 'object') return;
var newObj = obj instanceof Array ? [] : {};
for (var key in obj) {
// 不周遊原型鍊上的屬性,隻周遊自身屬性
if (obj.hasOwnProperty(key)) {
// 如果值是對象,就遞歸一下
if (obj[keys] && typeof obj[key ] === "object") {
newObj[key] = obj[key] instanceof Array ?[] : {};
// 如果是引用資料類型,會遞歸調用
newObj[key] = deepCopy(obj[key]);
} else {
// 如果不是,就直接指派
newObj = obj[keys];
}
}
}
return result;
}
補充:
淺拷貝:es6中有兩種新方法
方法1:
` let [...spread]= [12, 5, 8, 130, 44];
方法2:
Array.from(array)//建立一個新數組