在 JavaScript 中,深拷贝指的是创建一个新的对象,这个新的对象与原始对象完全独立,没有任何共享的属性或者数据,它们不共享同一块内存地址。深拷贝会复制原始对象的所有属性和嵌套对象的所有属性,包括嵌套对象中的属性。这意味着,修改拷贝后的对象不会影响原始对象。
深拷贝是一种常见的数据复制方式,它通常用于避免在操作对象时修改原始对象。在 JavaScript 中,可以使用多种方法进行深拷贝,包括递归遍历对象、lodash
的 deepClone
方法、使用 JSON 序列化和反序列化等方式。
JSON 序列化
利用 JSON 序列化和反序列化实现深拷贝,具体实现步骤如下:
- 使用
JSON.stringify()
方法将原始对象序列化为 JSON 字符串。 - 使用
JSON.parse()
方法将 JSON 字符串反序列化为新对象。
function deepClone(obj) {
return JSON.parse(JSON.stringify(obj));
}
const profile = {
name: "天行无忌",
city: "深圳",
};
const newProfile = deepClone(profile);
newProfile.city = "广东深圳";
console.log(profile); // { name: '天行无忌', city: '深圳' }
console.log(newProfile); // { name: '天行无忌', city: '广东深圳' }
使用 JSON 序列化和反序列化实现深拷贝存在一些局限性
- 无法复制函数、正则表达式等特殊对象类型。
- 无法复制对象的循环引用,即对象中存在自己或父对象的引用。
递归遍历对象
以下是一个使用递归遍历实现深拷贝的代码:
function deepClone(obj) {
if (obj === null || typeof obj !== "object") {
return obj;
}
let result = obj.constructor();
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
result[key] = deepClone(obj[key]);
}
}
return result;
}
const profile = {
name: "天行无忌",
city: "深圳",
};
const newProfile = deepClone(profile);
newProfile.city = "广东深圳";
console.log(profile); // { name: '天行无忌', city: '深圳' }
console.log(newProfile); // { name: '天行无忌', city: '广东深圳' }
使用 structuredClone
原生 structuredClone()
方法使用结构化克隆算法创建给定值的深层拷贝。
结构化克隆算法用于复制复杂 JavaScript 对象的算法。通过来自 Worker 的
postMessage()
或使用IndexedDB
存储对象时在内部使用。它通过递归输入对象来构建克隆,同时保持先前访问过的引用的映射,以避免无限遍历循环。
语法如下:
structuredClone(value)
structuredClone(value, { transfer })
value
:被克隆的对象。可以是任何结构化克隆支持的类型。transfer
:为可选参数,是一个可转移对象的数组,里面的 值 并没有被克隆,而是被转移到被拷贝对象上。
返回值:返回值是原始值的深拷贝。