深拷貝 & 淺拷貝
- 淺拷貝:僅僅是復(fù)制了引用屎慢,彼此之間的操作會(huì)互相影響
- 深拷貝:在堆中重新分配內(nèi)存瞭稼,不同的地址,相同的值腻惠,互不影響
總的來(lái)說(shuō)环肘,深淺拷貝的主要區(qū)別就是:復(fù)制的是引用還是復(fù)制的是實(shí)例
深淺拷貝的實(shí)現(xiàn)
看一看原生JavaScript中提供的一些復(fù)制方法究竟是深拷貝還是淺拷貝以及動(dòng)手實(shí)現(xiàn)深拷貝。
淺拷貝
- Array.prototype.slice()
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]
- Array.prototype.concat()
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]
看起來(lái)Array的slice(),concat()似乎是深拷貝集灌,再接著看就知道它們究竟是深拷貝還是淺拷貝:
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]
image.png
同樣廷臼,對(duì)于concat()也進(jìn)行驗(yàn)證:
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]
復(fù)制代碼
綜上, Array的slice和concat方法并不是真正的深拷貝绝页,對(duì)于Array的第一層的元素是深拷貝荠商,而Array的第二層 slice和concat方法是復(fù)制引用。所以续誉,Array的slice和concat方法都是淺拷貝莱没。
深拷貝
- JSON.parse()和JSON.stringify()
- JSON.stringify():把一個(gè)js對(duì)象序列化為一個(gè)JSON字符串
- JSON.parse():把JSON字符串反序列化為一個(gè)js對(duì)象
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'}}
image.png
綜上,JSON.parse()和JSON.stringify()是完全的深拷貝酷鸦。
- 動(dòng)手實(shí)現(xiàn)深拷貝 利用遞歸來(lái)實(shí)現(xiàn)對(duì)對(duì)象或數(shù)組的深拷貝饰躲。遞歸思路:對(duì)屬性中所有引用類型的值進(jìn)行遍歷,直到是基本類型值為止臼隔。
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) {
//只對(duì)對(duì)象自有屬性進(jìn)行拷貝
if (obj.hasOwnProperty(key)) {
if (obj[key] && typeof obj[key] === 'object') {
targetObj[key] = deepCopy(obj[key]);
} else {
targetObj[key] = obj[key];
}
}
}
return targetObj;
}