ECMAScript中的數據類型可分爲兩種:javascript
不一樣類型的存儲方式:java
不一樣類型的複製方式:數組
let foo = 1;
let bar = foo;
console.log(foo === bar); // -> true
// 修改foo變量的值並不會影響bar變量的值
let foo = 233;
console.log(foo); // -> 233
console.log(bar); // -> 1
複製代碼
let foo = {
name: 'leeper',
age: 20
}
let bar = foo;
console.log(foo === bar); // -> true
// 改變foo變量的值會影響bar變量的值
foo.age = 19;
console.log(foo); // -> {name: 'leeper', age: 19}
console.log(bar); // -> {name: 'leeper', age: 19}
複製代碼
總的來講,深淺拷貝的主要區別就是:複製的是引用仍是複製的是實例ui
看一看原生JavaScript中提供的一些複製方法到底是深拷貝仍是淺拷貝以及動手實現深拷貝。spa
let a = [1, 2, 3, 4];
let b = a.slice();
console.log(a === b); // -> false
a[0] = 5;
console.log(a); // -> [5, 2, 3, 4]
console.log(b); // -> [1, 2, 3, 4]
複製代碼
let a = [1, 2, 3, 4];
let b = a.concat();
console.log(a === b); // -> false
a[0] = 5;
console.log(a); // -> [5, 2, 3, 4]
console.log(b); // -> [1, 2, 3, 4]
複製代碼
看起來Array的slice(),concat()彷佛是深拷貝,再接着看就知道它們到底是深拷貝仍是淺拷貝:prototype
let a = [[1, 2], 3, 4];
let b = a.slice();
console.log(a === b); // -> false
a[0][0] = 0;
console.log(a); // -> [[0, 2], 3, 4]
console.log(b); // -> [[0, 2], 3, 4]
複製代碼
一樣,對於concat()也進行驗證:指針
let a = [[1, 2], 3, 4];
let b = a.concat();
console.log(a === b); // -> false
a[0][0] = 0;
console.log(a); // -> [[0, 2], 3, 4]
console.log(b); // -> [[0, 2], 3, 4]
複製代碼
綜上, Array的slice和concat方法並不是真正的深拷貝,對於Array的第一層的元素是深拷貝,而Array的第二層 slice和concat方法是複製引用。因此,Array的slice和concat方法都是淺拷貝。code
let obj = {
name: 'leeper',
age: 20,
friend: {
name: 'lee',
age: 19
}
};
let copyObj = JSON.parse(JSON.stringify(obj));
obj.name = 'Sandman';
obj.friend.name = 'Jerry';
console.log(obj);
// -> {name: "Sandman", age: 20, friend: {age: 19,name: 'Jerry'}}
console.log(copyObj);
// -> {name: "leeper", age: 20, friend: {age: 19,name: 'lee'}}
複製代碼
綜上,JSON.parse()和JSON.stringify()是徹底的深拷貝。cdn
function deepCopy(obj) {
if (!obj && typeof obj !== 'object') {
throw new Error('error arguments');
}
// const targetObj = obj.constructor === Array ? [] : {};
const targetObj = Array.isArray(obj) ? [] : {};
for (let key in obj) {
//只對對象自有屬性進行拷貝
if (obj.hasOwnProperty(key)) {
if (obj[key] && typeof obj[key] === 'object') {
targetObj[key] = deepCopy(obj[key]);
} else {
targetObj[key] = obj[key];
}
}
}
return targetObj;
}
複製代碼