Javascript 浅拷贝/深度拷贝的区别?
参考回答
在 JavaScript 中,浅拷贝(Shallow Copy)和深拷贝(Deep Copy)是指复制对象的不同方式。
- 浅拷贝:复制对象时,拷贝的是对象的引用,对于嵌套的对象,仍然指向原始对象中的子对象。
- 深拷贝:复制对象时,不仅复制对象本身,还会递归复制对象中嵌套的子对象,确保每个对象都是独立的。
详细讲解与拓展
1. 浅拷贝
浅拷贝是对对象的第一层属性进行拷贝。如果对象中的某个属性是引用类型(例如数组或对象),浅拷贝会复制引用,而不是复制值。也就是说,浅拷贝只是创建了一个新的对象,但对象内部的嵌套对象仍然引用的是原始对象中的嵌套对象。
例子:
const original = { a: 1, b: { c: 2 } };
const shallowCopy = { ...original };
shallowCopy.a = 3; // 修改第一层属性
shallowCopy.b.c = 4; // 修改嵌套对象的属性
console.log(original.a); // 1
console.log(original.b.c); // 4
console.log(shallowCopy.a); // 3
console.log(shallowCopy.b.c); // 4
在这个例子中,a 是一个简单类型,修改浅拷贝的 a 不会影响原对象的 a。但是,b 是一个对象,浅拷贝的 b 和原始对象的 b 仍然指向同一个对象,所以修改 b.c 会影响原始对象和拷贝对象。
常见的浅拷贝方法:
Object.assign()- 扩展运算符(
...)
2. 深度拷贝
深拷贝会递归地复制对象及其所有嵌套的对象。这样,拷贝后的对象与原始对象是完全独立的,即使是嵌套的对象也不会共享引用。
例子:
const original = { a: 1, b: { c: 2 } };
const deepCopy = JSON.parse(JSON.stringify(original));
deepCopy.a = 3; // 修改第一层属性
deepCopy.b.c = 4; // 修改嵌套对象的属性
console.log(original.a); // 1
console.log(original.b.c); // 2
console.log(deepCopy.a); // 3
console.log(deepCopy.b.c); // 4
在这个例子中,JSON.parse(JSON.stringify()) 是一种常见的深拷贝方法,它会创建一个新对象,并递归地拷贝原始对象的所有属性,包括嵌套的对象。因此,修改深拷贝的 a 或 b.c 不会影响原始对象。
常见的深拷贝方法:
JSON.parse(JSON.stringify())(适用于无函数和undefined的简单对象)- 使用第三方库,如 Lodash 的
_.cloneDeep()
注意点:
JSON.parse(JSON.stringify())的局限性:这种方法不能处理包含undefined、函数、循环引用等复杂结构的对象。例如:const obj = { a: undefined, b: function() {} }; const deepCopy = JSON.parse(JSON.stringify(obj)); // 这会丢失 `a` 和 `b`- 性能考虑:对于复杂的对象,使用深拷贝可能会影响性能,因为它需要递归遍历所有嵌套的属性。
扩展:深拷贝与循环引用
如果对象中包含循环引用(例如,一个对象引用自身),JSON.parse(JSON.stringify()) 会抛出错误。可以使用像 Lodash 这样的库来处理这些特殊情况。
const obj = {};
obj.self = obj;
const deepCopy = _.cloneDeep(obj); // 使用 Lodash 可以处理循环引用
总结
- 浅拷贝:只拷贝对象的第一层属性,对于引用类型的属性,拷贝的是引用(地址),改变嵌套对象会影响到原对象。
- 深拷贝:递归拷贝对象的所有属性,包括嵌套的对象,确保每个对象都是独立的,不会相互影响。