851 字
4 分钟
深拷贝与浅拷贝
2025-10-07

数据类型#

JavaScript 中的数据类型可以分为两大类:基本数据类型和引用数据类型。

  • 基本数据类型:包括 NumberStringBooleannullundefinedSymbol。这些类型的值是不可变的,直接存储在栈内存中。
  • 引用数据类型:包括 ObjectArrayFunction 等。这些类型的值是可变的,存储在堆内存中,变量存储的是指向堆内存中实际数据的引用。

浅拷贝#

浅拷贝是指创建一个新对象,这个新对象有着原始对象属性值的一份精确拷贝。如果属性值是基本数据类型,拷贝的是值本身;如果属性值是引用数据类型,拷贝的是内存地址(引用),因此两个对象会共享同一个引用对象。

实现浅拷贝的方法#

  1. Object.assign()
const original = { a: 1, b: { c: 2 } };
const shallowCopy = Object.assign({}, original);
shallowCopy.a = 10;
shallowCopy.b.c = 3;
console.log(original); // { a: 1, b: { c: 3 } }
console.log(shallowCopy); // { a: 10, b: { c: 3 } }
  1. 扩展运算符(Spread Operator)
const original = { a: 1, b: { c: 2 } };
const shallowCopy = { ...original };
shallowCopy.a = 10;
shallowCopy.b.c = 3;
console.log(original); // { a: 1, b: { c: 3 } }
console.log(shallowCopy); // { a: 10, b: { c: 3 } }
  1. Array.prototype.slice(), Array.prototype.concat()(用于数组)
const originalArray = [1, 2, { a: 3 }];
const shallowCopyArray = originalArray.slice();
const anotherShallowCopyArray = originalArray.concat();
shallowCopyArray[0] = 10;
shallowCopyArray[2].a = 4;
console.log(originalArray); // [1, 2, { a: 4 }]
console.log(shallowCopyArray); // [10, 2, { a: 4 }]
console.log(anotherShallowCopyArray); // [1, 2, { a: 4 }]
  1. 手动实现浅拷贝函数
function shallowClone(obj) {
if (obj === null || typeof obj !== "object") {
return obj; // 处理基本数据类型
}
const clone = {};
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
clone[key] = obj[key];
}
}
return clone;
}

深拷贝#

深拷贝是指创建一个新对象,这个新对象与原始对象完全独立,且包含原始对象所有属性的递归拷贝。如果属性值是基本数据类型,拷贝的是值本身;如果属性值是引用数据类型,拷贝的是该引用对象的一个全新副本。

实现深拷贝的方法#

  1. JSON.parse() 和 JSON.stringify()
const original = { a: 1, b: { c: 2 } };
const deepCopy = JSON.parse(JSON.stringify(original));
deepCopy.b.c = 3;
console.log(original); // { a: 1, b: { c: 2 } }
console.log(deepCopy); // { a: 1, b: { c: 3 } }

这种方法简单但有局限性,不能拷贝 functionundefinedsymbol

  1. 递归函数
function deepClone(obj, hash = new WeakMap()) {
if (obj === null || typeof obj !== "object") {
return obj; // 处理基本数据类型
}
if (obj instanceof Date) {
return new Date(obj);
}
if (obj instanceof RegExp) {
return new RegExp(obj);
}
if (hash.has(obj)) {
return hash.get(obj); // 处理循环引用
}
let clone = new obj.constructor();
hash.set(obj, clone);
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
clone[key] = deepClone(obj[key], hash);
}
}
return clone;
}

区别#

  • 内存分配:浅拷贝只复制对象的第一层属性,引用类型的属性仍然指向同一个内存地址;深拷贝则是递归复制所有层级的属性,完全独立。
  • 性能:浅拷贝通常比深拷贝更快,因为它只复制一层属性;深拷贝由于需要递归处理,性能开销较大。
  • 适用场景:浅拷贝适用于对象属性较为简单且不包含嵌套对象的情况;深拷贝适用于需要完全独立的对象,尤其是包含嵌套对象的情况。
  • 循环引用:浅拷贝不会处理循环引用的问题,而深拷贝需要特别处理循环引用以避免无限递归。
深拷贝与浅拷贝
https://fuyuki.fun/posts/前端/深拷贝与浅拷贝/
作者
Fuyuki_Vila
发布于
2025-10-07
许可协议
CC BY-NC-SA 4.0
Music Off