浅拷贝 (Shallow Copy)
浅拷贝只复制对象的第一层属性,如果属性是引用类型,则复制的是引用(内存地址),而不是实际的值。
浅拷贝的实现方式
-
展开运算符 (...)
const original = { a: 1, b: { c: 2 } }; const shallowCopy = { ...original }; -
Object.assign()
const original = { a: 1, b: { c: 2 } }; const shallowCopy = Object.assign({}, original); -
数组的浅拷贝方法
const originalArray = [1, 2, { a: 3 }]; const shallowCopyArray = originalArray.slice(); // 或 const shallowCopyArray2 = [...originalArray]; // 或 const shallowCopyArray3 = originalArray.concat();
浅拷贝的问题
const original = { a: 1, b: { c: 2 } };
const shallowCopy = { ...original };
original.a = 10; // 不会影响浅拷贝
original.b.c = 20; // 会影响浅拷贝,因为b是引用类型
console.log(shallowCopy.a); // 1 (未受影响)
console.log(shallowCopy.b.c); // 20 (受影响)
深拷贝 (Deep Copy)
深拷贝会复制对象的所有层级,创建一个完全独立的新对象,包括所有嵌套的对象和数组。
深拷贝的实现方式
-
JSON.parse(JSON.stringify())
const original = { a: 1, b: { c: 2 } }; const deepCopy = JSON.parse(JSON.stringify(original));- 缺点:无法处理函数、Symbol、undefined、循环引用等
-
使用第三方库
-
Lodash 的
_.cloneDeep()const _ = require('lodash'); const original = { a: 1, b: { c: 2 } }; const deepCopy = _.cloneDeep(original);
-
-
手动实现深拷贝
function deepClone(obj, hash = new WeakMap()) { if (obj === null || typeof obj !== 'object') return obj; if (hash.has(obj)) return hash.get(obj); const result = Array.isArray(obj) ? [] : {}; hash.set(obj, result); for (let key in obj) { if (obj.hasOwnProperty(key)) { result[key] = deepClone(obj[key], hash); } } return result; } -
现代浏览器 API
-
structuredClone()const original = { a: 1, b: { c: 2 } }; const deepCopy = structuredClone(original);
-
深拷贝的注意事项
const obj = {
a: 1,
b: { c: 2 },
d: new Date(),
e: function() { console.log('e'); },
f: undefined,
g: Symbol('sym'),
h: new RegExp(/abc/, 'g')
};
// JSON方法会丢失函数、undefined、Symbol等
const jsonCopy = JSON.parse(JSON.stringify(obj));
console.log(jsonCopy); // { a: 1, b: { c: 2 }, d: "ISO日期字符串", h: {} }
// structuredClone可以处理更多类型但不能处理函数
const structuredCopy = structuredClone(obj); // 会报错,因为不能克隆函数
如何选择
- 如果对象没有嵌套或嵌套的都是基本类型,使用浅拷贝
- 如果需要完全独立的副本,使用深拷贝
- 对于复杂对象的深拷贝,推荐使用
structuredClone()或 Lodash 的_.cloneDeep()
循环引用问题
const obj = { a: 1 };
obj.self = obj;
// JSON方法会报错
// JSON.parse(JSON.stringify(obj)); // TypeError: Converting circular structure to JSON
// 使用带有WeakMap的手动实现可以解决
const cloned = deepClone(obj); // 使用上面的手动实现
console.log(cloned.self === cloned); // true
深拷贝和浅拷贝是JavaScript中处理对象复制的重要概念,理解它们的区别和适用场景对于编写健壮的代码非常重要。