在 JavaScript 中,深度拷贝是指创建一个新的对象或数组,它的值与原始对象或数组相同,但在内存中是完全独立的副本,对新对象或数组的修改不会影响原始对象。以下是几种常见的深度拷贝方式:
-
使用 JSON.parse () 和 JSON.stringify ()
-
原理:先将对象转换为 JSON 字符串,然后再将 JSON 字符串解析回对象。因为 JSON 字符串是独立于原始对象的新数据结构,这样就可以实现深度拷贝。
-
示例代码:
-
收起
javascript
复制
let originalObject = {
name: "John",
age: 30,
hobbies: ["reading", "coding"]
};
let copiedObject = JSON.parse(JSON.stringify(originalObject));
copiedObject.name = "Jane";
copiedObject.hobbies.push("swimming");
console.log(originalObject);
console.log(copiedObject);
-
注意事项:
-
这种方法有一定的局限性。它不能拷贝函数、
Symbol
类型的值和循环引用的对象。例如,如果对象中有一个函数属性,在序列化和反序列化的过程中,函数会丢失。 -
对于日期对象,它会被转换为 ISO 字符串,在反序列化后得到的是一个新的日期对象,其内部的时间戳等信息与原始日期对象相同,但它们在内存中是不同的实例。
-
-
递归拷贝(对于简单对象和数组)
-
原理:对于对象或数组的每个属性或元素进行遍历,如果属性值是对象或数组,就递归地进行拷贝。
-
示例代码:
-
收起
javascript
复制
function deepCopy(obj) {
if (typeof obj!== 'object' || obj === null) {
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;
}
let originalObject = {
name: "John",
age: 30,
hobbies: ["reading", "coding"]
};
let copiedObject = deepCopy(originalObject);
copiedObject.name = "Jane";
copiedObject.hobbies.push("swimming");
console.log(originalObject);
console.log(copiedObject);
-
注意事项:
-
这种方法可以处理复杂的嵌套对象和数组,包括包含函数等自定义类型的对象。但是,如果对象存在循环引用(例如,对象 A 的一个属性引用对象 A 本身),会导致栈溢出错误,需要特殊处理来避免这种情况。
-
-
使用第三方库(如 Lodash 的
_.cloneDeep()
)-
原理:像 Lodash 这样的库提供了经过优化和测试的深度拷贝函数。
_.cloneDeep()
内部实现了复杂的逻辑来处理各种数据类型、循环引用等情况。 -
示例代码:
-
收起
javascript
复制
const _ = require('lodash');
let originalObject = {
name: "John",
age: 30,
hobbies: ["reading", "coding"]
};
let copiedObject = _.cloneDeep(originalObject);
copiedObject.name = "Jane";
copiedObject.hobbies.push("swimming");
console.log(originalObject);
console.log(copiedObject);
-
注意事项:
- 需要引入 Lodash 库。在项目中引入第三方库会增加项目的体积和依赖关系,需要考虑对项目的影响。不过,Lodash 提供了很多实用的工具函数,在复杂的开发场景中可能会带来更多便利。