JavaScript 中的深拷贝是创建一个与原始对象完全独立的新对象,新对象中的属性值是原始对象属性值的一个拷贝,而不是引用。这意味着,如果你修改新对象,原始对象不会受到影响,反之亦然。
以下是一些实现深拷贝的常见方法:
1. JSON 方法
使用 JSON.stringify() 和 JSON.parse() 可以实现深拷贝,但这种方法有一些限制:
* 它不能复制函数和循环引用的对象。
* 它不能复制 Date 对象、RegExp 对象等特殊对象,因为 JSON.stringify() 会将它们转换为字符串。
* 它可能会丢失对象的某些属性,如 `undefined`、`Symbol` 类型的属性和函数的 `prototype` 属性。
function deepCopy(obj) {
return JSON.parse(JSON.stringify(obj));
}
2. 手动递归复制
通过递归遍历对象的所有属性,并逐个复制,可以实现深拷贝。这种方法可以处理函数和特殊对象,但需要更多的代码。
function deepCopy(obj, hash = new WeakMap()) {
if (typeof obj !== 'object' || obj === null) {
return obj;
}
// 如果已经是循环引用,则直接返回引用
if (hash.has(obj)) {
return hash.get(obj);
}
let newObj = Array.isArray(obj) ? [] : {};
hash.set(obj, newObj);
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] = deepCopy(obj[key], hash);
}
}
return newObj;
}
这个 deepCopy 函数使用了 WeakMap 来跟踪已经访问过的对象,从而避免无限循环。对于每个对象,如果它已经被访问过,就直接返回它的引用;否则,创建一个新的对象,并递归地复制它的所有属性。
3. 使用第三方库
如 lodash 的 _.cloneDeep() 方法也可以实现深拷贝。
const _ = require('lodash');
let obj = { a: 1, b: { c: 3 } };
let newObj = _.cloneDeep(obj);
总的来说,选择哪种深拷贝方法取决于你的具体需求。如果你的对象结构相对简单,没有循环引用或特殊对象,那么 JSON.stringify() 和 JSON.parse() 可能是一个简单而有效的选择。然而,如果你的对象结构更复杂,包含循环引用或特殊对象,那么你可能需要手动实现深拷贝或使用第三方库。