浅拷贝复制对象的引用而不是对象本身,这意味着拷贝后的对象与原对象共享同一个引用。如果原对象中的某个属性是对象类型,那么浅拷贝只会复制这个引用,而不是这个对象。
Object.assign():
const obj1 = { a: 1, b: { c: 2 } };
const obj2 = Object.assign({}, obj1);
扩展运算符:
const obj1 = { a: 1, b: { c: 2 } };
const obj2 = { ...obj1 };
数组的slice()方法:
const arr1 = [1, 2, { a: 3 }];
const arr2 = arr1.slice();
在上述例子中,obj2
和 arr2
中的嵌套对象 b
和 { a: 3 }
与 obj1
和 arr1
中的对应对象共享同一个引用。
深拷贝会递归地复制对象的所有层级,确保新对象与原对象完全独立,任何一方的修改都不会影响另一方。
JSON.stringify() 和 JSON.parse():
const obj1 = { a: 1, b: { c: 2 } };
const obj2 = JSON.parse(JSON.stringify(obj1));
注意:这种方法有局限性,它不能拷贝函数、Date
对象、undefined
、Infinity
、NaN
等特殊值,并且无法处理循环引用。
递归方法:
这是一个更通用的方法,可以处理上述方法的局限性。
function deepCopy(obj, hash = new WeakMap()) {
if (obj === null || typeof obj !== 'object') {
return obj;
}
if (hash.has(obj)) {
return hash.get(obj);
}
let copy = Array.isArray(obj) ? [] : {};
hash.set(obj, copy);
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
copy[key] = deepCopy(obj[key], hash);
}
}
return copy;
}
const obj1 = { a: 1, b: { c: 2 }, d: function() { return 3; }, e: new Date() };
const obj2 = deepCopy(obj1);
这个 deepCopy
函数使用了递归来处理对象的每一层,并且利用 WeakMap
来处理循环引用的问题。
浅拷贝:
深拷贝:
以下是一个处理更多情况的完整深拷贝函数,包括数组、对象、Date
对象、正则表达式、循环引用等:
function deepCopy(obj, hash = new WeakMap()) {
// 如果obj是null或不是对象,直接返回它(这是基本类型的情况)
if (obj === null || typeof obj !== 'object') {
return obj;
}
// 处理Date对象的情况
if (obj instanceof Date) {
return new Date(obj);
}
// 处理RegExp对象的情况
if (obj instanceof RegExp) {
return new RegExp(obj);
}
// 如果已经处理过这个对象,直接返回之前的拷贝(处理循环引用的情况)
if (hash.has(obj)) {
return hash.get(obj);
}
// 创建对象或数组的拷贝
let copy = Array.isArray(obj) ? [] : {};
// 记录这个对象及其拷贝(用于处理循环引用)
hash.set(obj, copy);
// 遍历对象的所有属性
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
// 递归拷贝每个属性
copy[key] = deepCopy(obj[key], hash);
}
}
return copy; // 返回深拷贝的对象
}
// 测试示例
const obj1 = {
a: 1,
b: { c: 2 },
d: function() { return 3; },
e: new Date(),
f: /abc/g,
g: [1, 2, 3],
h: null
};
const obj2 = deepCopy(obj1);
console.log(obj2);
基本类型处理:
if (obj === null || typeof obj !== 'object') {
return obj;
}
obj
是 null
或者不是对象类型(包括基本类型),直接返回它。Date 对象处理:
if (obj instanceof Date) {
return new Date(obj);
}
obj
是 Date
对象,创建一个新的 Date
实例并返回。RegExp 对象处理:
if (obj instanceof RegExp) {
return new RegExp(obj);
}
obj
是 RegExp
对象,创建一个新的 RegExp
实例并返回。循环引用处理:
if (hash.has(obj)) {
return hash.get(obj);
}
hash
中已经有这个对象,说明它是循环引用的一部分,直接返回之前的拷贝。创建拷贝:
let copy = Array.isArray(obj) ? [] : {};
hash.set(obj, copy);
obj
是数组,则创建一个新的空数组;否则,创建一个新的空对象。WeakMap
记录这个对象及其拷贝,用于处理循环引用。递归拷贝属性:
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
copy[key] = deepCopy(obj[key], hash);
}
}
obj
的所有属性,对于每个属性递归调用 deepCopy
。const obj1 = {
a: 1,
b: { c: 2 },
d: function() { return 3; },
e: new Date(),
f: /abc/g,
g: [1, 2, 3],
h: null
};
const obj2 = deepCopy(obj1);
console.log(obj2);
obj1
包含各种类型的数据,包括对象、数组、函数、Date
对象、正则表达式和 null
。deepCopy
函数对 obj1
进行深拷贝,生成 obj2
。console.log(obj2)
输出拷贝后的对象,验证深拷贝是否正确。