在 JavaScript 中,对象的复制通常分为两种类型:深拷贝和浅拷贝。这两种拷贝方式在处理对象和数组时有不同的影响,因此在开发中选择适当的拷贝方式非常重要。让我们深入了解这两种拷贝方式以及它们的区别。
1. 浅拷贝
浅拷贝是指复制一个对象,创建一个新对象,但仅复制原始对象的第一层结构。换句话说,如果原始对象包含引用类型(例如对象或数组),则浅拷贝只会复制引用而不会复制引用指向的对象本身。
1.1 使用 Object.assign()
js
const originalObject = { a: 1, b: { c: 2 } };
const shallowCopy = Object.assign({}, originalObject);
console.log(shallowCopy);
// 输出: { a: 1, b: { c: 2 } }
console.log(originalObject.b === shallowCopy.b);
// 输出: true
1.2 使用展开运算符(Spread Operator)
js
const originalObject = { a: 1, b: { c: 2 } };
const shallowCopy = { ...originalObject };
console.log(shallowCopy);
// 输出: { a: 1, b: { c: 2 } }
console.log(originalObject.b === shallowCopy.b);
// 输出: true
浅拷贝的缺点在于,如果原始对象的属性值是引用类型,那么浅拷贝后的对象仍然会共享这些引用类型的值。
2. 深拷贝
深拷贝是指创建一个新对象,并递归地复制原始对象的所有嵌套属性,包括引用类型。这确保了原始对象和拷贝后的对象是完全独立的,不共享任何引用类型的值。
2.1 使用递归实现深拷贝
js
function deepCopy(obj) {
if (typeof obj !== 'object' || obj === null) {
return obj; // 非对象或 null 直接返回
}
let copy = Array.isArray(obj) ? [] : {};
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
copy[key] = deepCopy(obj[key]);
}
}
return copy;
}
const originalObject = { a: 1, b: { c: 2 } };
const deepCopyObject = deepCopy(originalObject);
console.log(deepCopyObject);
// 输出: { a: 1, b: { c: 2 } }
console.log(originalObject.b === deepCopyObject.b);
// 输出: false
2.2 使用 JSON 序列化与反序列化
js
const originalObject = { a: 1, b: { c: 2 } };
const deepCopyObject = JSON.parse(JSON.stringify(originalObject));
console.log(deepCopyObject);
// 输出: { a: 1, b: { c: 2 } }
console.log(originalObject.b === deepCopyObject.b);
// 输出: false
需要注意的是,使用 JSON 序列化和反序列化的方法有一些限制,例如无法处理包含函数、正则表达式等特殊对象。
手写一个浅拷贝
js
function shalldowCopy(obj) {
if (typeof obj !== 'object' || obj == null) return //只拷贝引用类型
let objCopy = obj instanceof Array ? [] : {}
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
objCopy[key] = obj[key]
}
}
return objCopy
}
总结
选择深拷贝还是浅拷贝取决于你的需求。浅拷贝通常足够满足简单的场景,但在涉及复杂嵌套结构、共享状态或需要保留原始对象与拷贝对象完全独立的情况下,深拷贝是更安全的选择。在实际开发中,根据具体情况选择合适的拷贝方式是非常重要的。