在JavaScript开发中,对象拷贝是一个常见但容易出错的操作。理解浅复制(shallow copy)和深复制(deep copy)的区别及实现方式,对于编写健壮的JavaScript代码至关重要。
浅复制(Shallow Copy)
浅复制只复制对象的第一层属性,如果属性值是引用类型(如对象、数组等),则复制的是引用而非实际对象本身。
浅复制的实现方式
- 展开运算符(...)
javascript
const original = { a: 1, b: { c: 2 } };
const shallowCopy = { ...original };
- Object.assign()
javascript
const original = { a: 1, b: { c: 2 } };
const shallowCopy = Object.assign({}, original);
- 数组的浅复制
javascript
const originalArray = [1, 2, { a: 3 }];
const shallowCopyArray = [...originalArray];
// 或
const shallowCopyArray2 = originalArray.slice();
深复制(Deep Copy)
深复制会递归复制对象的所有层级,创建一个完全独立的副本。
深复制的实现方式
- JSON方法(有局限性)
javascript
const original = { a: 1, b: { c: 2 } };
const deepCopy = JSON.parse(JSON.stringify(original));
注意:此方法无法复制函数、Symbol、undefined等特殊类型
- 递归实现
javascript
function deepClone(obj) {
if (obj === null || typeof obj !== 'object') {
return obj;
}
if (obj instanceof Date) {
return new Date(obj.getTime());
}
if (obj instanceof Array) {
const copy = [];
for (let i = 0; i < obj.length; i++) {
copy[i] = deepClone(obj[i]);
}
return copy;
}
if (obj instanceof Object) {
const copy = {};
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
copy[key] = deepClone(obj[key]);
}
}
return copy;
}
throw new Error("Unable to copy object");
}
- 使用第三方库
javascript
// 使用lodash
const _ = require('lodash');
const deepCopy = _.cloneDeep(original);
性能与选择考虑
- 浅复制:速度快,内存占用少,适合简单对象或确定嵌套结构不会改变的情况
- 深复制:更安全但性能开销大,适合复杂对象或不确定嵌套结构是否会改变的情况
原型链与拷贝
当拷贝对象涉及原型链时,需要注意:
javascript
function Person(name) {
this.name = name;
}
Person.prototype.greet = function() {
console.log(`Hello, ${this.name}`);
};
const john = new Person('John');
const shallowCopy = { ...john }; // 会丢失原型方法
const deepCopy = deepClone(john); // 也会丢失原型方法
// 保持原型链的拷贝
const protoCopy = Object.create(
Object.getPrototypeOf(john),
Object.getOwnPropertyDescriptors(john)
);
在实际开发中,应根据具体需求选择合适的拷贝方式,理解每种方式的优缺点,才能写出更健壮的代码。