JavaScript 深拷贝和浅拷贝
2022-03-24 本文已影响0人
暴躁程序员
拷贝的意思就是复制数据,打个比方,原有一个变量 a 的值是引用类型数据,要求新创建的变量 b 的值与 a 的值相同,
方案一(浅拷贝):让 b 直接共享a 的数据,那么 a 和 b 任何一方修改数据,另一方的数据也会同步变化
方案二(深拷贝):让 b 创建一个新的空间用来存储和 a 一样的数据,即 将 a 的数据,以递归的方式拷贝到 b 新创建的数据空间中
注意:
- 基础数据类型的值存储于栈中,他不涉及深浅拷贝(全是深拷贝)
- 引用类型的地址存储于栈中,指针指向存储于堆中的值,且其他变量的指针可通过赋值的方式指向同一个堆中的值,当堆中的值发生改变时,会造成所有变量的值同步变化
总结:浅拷贝 --- 拷贝引用类型的地址,深拷贝 --- 拷贝引用类型的值
浅拷贝
-
变量赋值
的方式实现 数组和对象 的浅拷贝
// 数组浅拷贝
let a = [1, 2, 3, 4, 5];
let b = a;
b[0] = 1000; // 改变 b 的时候,同时也会改变 a
console.log(a); // [ 1000, 2, 3, 4, 5 ]
// 对象浅拷贝
let c = { name: 1, age: 1 };
let d = c;
d.name = 1000; // 改变 d 的时候,同时也会改变 c
console.log(c); // { name: 1000, age: 1 }
-
Object.assign()
实现 对象 浅拷贝
// 对象浅拷贝
let a = { name: 1, age: 1 };
let b = Object.assign(a, { other: 999 });
b.name = 1000; // 改变 b 的时候,同时也会改变 a
console.log(a); // { name: 1000, age: 1, other: 999 }
// 注意:Object.assign的用法,a 写在第一位才是浅拷贝,写成Object.assign({ other: 999 }, a) ,是深拷贝
let c = Object.assign({ other: 999 }, a);
c.name = 888; // 改变 c 的时候,a 不会变化
console.log(a); // { name: 1000, age: 1, other: 999 }
深拷贝
-
递归
的方式实现 数组和对象 的深拷贝
// 数组深拷贝
let a = [1, 2, 3, 4, 5];
let b = [];
for (let i = 0; i < a.length; i++) {
b.push(a[i]);
}
b[0] = 1000; // 改变 b 的时候,a 不受影响
console.log(b); // [ 1000, 2, 3, 4, 5 ]
console.log(a); // [ 1, 2, 3, 4, 5 ]
// 对象深拷贝
let c = { name: 1, age: 1 };
let d = {};
for (const k in c) {
if (Object.hasOwnProperty.call(c, k)) {
d[k] = c[k];
}
}
d.name = 1000; // 改变 d 的时候,c 不受影响
console.log(c); // { name: 1, age: 1 }
console.log(d); // { name: 1000, age: 1 }
-
...
拓展运算符
的方式实现 数组和对象 的深拷贝
// 数组深拷贝
let a = [1, 2, 3, 4, 5];
let b = [...a];
b[0] = 1000; // 改变 b 的时候,a 的值不变
console.log(a); // [1, 2, 3, 4, 5];
console.log(b); // [ 1000, 2, 3, 4, 5 ]
// 对象深拷贝
let c = { name: 1, age: 1 };
let d = { ...c };
d.name = 1000; // 改变 d 的时候,c 的值不会变
console.log(c); // { name: 1, age: 1 }
console.log(d); // { name: 1000, age: 1
- 数组的
slice
、concat
方法实现 数组 的深拷贝
// slice 实现 数组深拷贝
let a = [1, 2, 3, 4, 5];
let b = a.slice();
b[0] = 1000; // 改变 b 的时候,a 的值不变
console.log(a); // [1, 2, 3, 4, 5];
console.log(b); // [ 1000, 2, 3, 4, 5 ]
// concat 实现 数组深拷贝
let c = [1, 2, 3, 4, 5];
let d = a.concat();
d[0] = 1000; // 改变 b 的时候,a 的值不变
console.log(c); // [1, 2, 3, 4, 5];
console.log(d); // [ 1000, 2, 3, 4, 5 ]