JS - 深拷贝 & 浅拷贝
介绍了常见的js 深拷贝与浅拷贝方法, 以及手写深拷贝。
client preview
在理解拷贝机制前,需要了解JavaScript的内存模型:
栈内存:存储基本类型值(Number、String、Boolean等)和对象引用
堆内存:存储复杂对象(Object、Array等)
浅拷贝
创建一个新对象,复制原始对象的第一层属性:
特点:
基本类型值被复制
引用类型属性被共享(复制引用地址)
修改嵌套对象会影响原始对象
数组浅拷贝
我们通常使用slice()
, concat()
, 扩展运算符...
对数组进行浅拷贝。
javascript
let arr = [1, 2, 3, 4, { value: 5 }];
const arr1 = arr.concat();
const arr2 = arr.slice();
const arr3 = [...arr]
arr[4].value = 6;
console.log(arr1); //[1, 2, 3, 4, { value: 6 }]
console.log(arr2); //[1, 2, 3, 4, { value: 6 }]
console.log(arr3); //[1, 2, 3, 4, { value: 6 }]
数组里有对象,那么不会拷贝对象的值,而是拷贝对象的引用,原来数据对象的值发生改变,由于拷贝的是对象的引用,新拷贝的数组中对象的值也发生改变,拷贝的不是很彻底,slice()
concat()
扩展运算符...
是浅拷贝
对象浅拷贝
对于对象的浅拷贝通常使用扩展运算符...
和assign()
javascript
let obj = {
name: "slim",
address: { city: "shanghai" }
}
const obj1 = Object.assign({}, obj);
const obj2 = { ...obj };
obj.address.city = "hebei";
console.log(obj1); //{ name: 'slim', address: { city: 'hebei' } }
console.log(obj2); //{ name: 'slim', address: { city: 'hebei' } }
深拷贝
创建一个完全独立的对象副本,递归复制所有层级:
特点:
所有层级都被复制
嵌套对象也是新创建的
修改副本不影响原始对象
JSON.stringfy
javascript
let arr = [1, 2, 3, 4, { value: 5 }];
const arr1 = JSON.parse(JSON.stringify(arr));
arr[4].value = 6;
console.log(arr1); //[1, 2, 3, 4, { value: 5 }]
var obj = {
name: "slim",
address: { city: "shanghai" }
}
var obj1 = JSON.parse(JSON.stringify(obj));
obj.address.city = "hebei";
console.log(obj1); //{ name: 'slim', address: { city: 'shanghai' } }
可以看到JSON.stringfy 实现了对象的深拷贝,但该方法有一定的局限性,不能对undefined
symbol
函数
进行深度拷贝。
递归实现
javascript
function deepClone(target) {
if (typeof target !== 'object') {
return;
}
const newObj = Array.isArray(target) ? [] : {};
for (let key in target) {
if (target.hasOwnProperty(key)) {
newObj[key] = typeof target[key] === 'object' ? deepClone(target[key]) : target[key];
}
}
return newObj;
}
