在 JavaScript 里,对象的浅拷贝和深拷贝是两个重要概念,它们在处理对象复制时存在明显差异。
浅拷贝
浅拷贝会创建一个新对象,新对象的属性与原对象相同。不过,对于引用类型的属性,浅拷贝仅仅复制其引用,而非对象本身。这就意味着,原对象和新对象会共享这些引用类型的属性。
以下是几种实现浅拷贝的常用方法:
- 扩展运算符(Spread Operator)
const original = { a: 1, b: { c: 2 } };
const shallowCopy = { ...original };
console.log(shallowCopy); // { a: 1, b: { c: 2 } }
console.log(shallowCopy.b === original.b); // true(引用相同)
- Object.assign()
const original = { a: 1, b: { c: 2 } };
const shallowCopy = Object.assign({}, original);
console.log(shallowCopy); // { a: 1, b: { c: 2 } }
console.log(shallowCopy.b === original.b); // true(引用相同)
- 手动复制
function shallowCopy(obj) {
const copy = {};
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
copy[key] = obj[key];
}
}
return copy;
}
const original = { a: 1, b: { c: 2 } };
const shallowCopy = shallowCopy(original);
console.log(shallowCopy); // { a: 1, b: { c: 2 } }
console.log(shallowCopy.b === original.b); // true(引用相同)
深拷贝
深拷贝同样会创建一个新对象。但不同的是,深拷贝会递归地复制原对象的所有属性,包括嵌套的对象,从而让新对象和原对象完全独立,不共享任何引用。
下面是实现深拷贝的方法
1.JSON.parse () 和 JSON.stringify ()
const original = { a: 1, b: { c: 2 } };
const deepCopy = JSON.parse(JSON.stringify(original));
console.log(deepCopy); // { a: 1, b: { c: 2 } }
console.log(deepCopy.b === original.b); // false(引用不同)
不过,这种方法存在局限性,它无法处理函数、正则表达式、日期对象等特殊对象。
2. 递归实现深拷贝函数
function deepCopy(obj) {
if (obj === null || typeof obj !== 'object') {
return obj;
}
let copy;
if (Array.isArray(obj)) {
copy = [];
for (let i = 0; i < obj.length; i++) {
copy[i] = deepCopy(obj[i]);
}
} else {
copy = {};
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
copy[key] = deepCopy(obj[key]);
}
}
}
return copy;
}
const original = { a: 1, b: { c: 2 } };
const deepCopy = deepCopy(original);
console.log(deepCopy); // { a: 1, b: { c: 2 } }
console.log(deepCopy.b === original.b); // false(引用不同)
总结
- 浅拷贝:仅复制对象的一层属性,适合处理简单对象,能提高性能。
- 深拷贝:会递归复制所有嵌套对象,适用于需要完全独立副本的场景,但要注意其性能开销和特殊对象处理的局限性。
在实际编程中,你要依据具体需求来选择合适的拷贝方式。如果需要处理复杂对象的深拷贝,也可以考虑使用像 Lodash 的 _.cloneDeep 这样的第三方库。
const _ = require('lodash');
// 定义一个包含嵌套结构的原始对象
const originalObject = {
name: 'John',
age: 30,
address: {
city: 'New York',
zip: '10001'
},
hobbies: ['reading', 'coding'],
details: {
education: {
degree: 'Master',
school: 'Columbia University'
}
}
};
// 使用lodash的cloneDeep方法进行深拷贝
const clonedObject = _.cloneDeep(originalObject);
// 修改克隆对象的嵌套属性
clonedObject.address.city = 'San Francisco';
clonedObject.hobbies.push('painting');
clonedObject.details.education.school = 'Stanford University';
// 验证原始对象是否保持不变
console.log('原始对象地址:', originalObject.address.city);
// 输出: New York
console.log('克隆对象地址:', clonedObject.address.city);
// 输出: San Francisco
console.log('原始对象爱好:', originalObject.hobbies);
// 输出: ['reading', 'coding']
console.log('克隆对象爱好:', clonedObject.hobbies);
// 输出: ['reading', 'coding', 'painting']
console.log('原始对象学校:', originalObject.details.education.school);
// 输出: Columbia University
console.log('克隆对象学校:', clonedObject.details.education.school);
// 输出: Stanford University
// 验证引用是否不同
console.log('地址对象引用是否相同:', originalObject.address === clonedObject.address);
// 输出: false
console.log('爱好数组引用是否相同:', originalObject.hobbies === clonedObject.hobbies);
// 输出: false
console.log('教育对象引用是否相同:',
originalObject.details.education === clonedObject.details.education);
// 输出: false