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()) 是一种常见的深拷贝方法,它会创建一个新对象,并递归地拷贝原始对象的所有属性,包括嵌套的对象。因此,修改深拷贝的 ab.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 可以处理循环引用

总结

  • 浅拷贝:只拷贝对象的第一层属性,对于引用类型的属性,拷贝的是引用(地址),改变嵌套对象会影响到原对象。
  • 深拷贝:递归拷贝对象的所有属性,包括嵌套的对象,确保每个对象都是独立的,不会相互影响。

发表评论

后才能评论