深拷贝和浅拷贝是两种不同的复制对象的方式。
深拷贝会创建一个新的对象,并复制原始对象的所有属性和值,包括嵌套对象。
浅拷贝只会创建一个新的对象,并复制原始对象的引用,而不是值。这意味着对浅拷贝的更改也会影响原始对象。
深拷贝的实现方式
- 递归:这是最常见的一种实现深拷贝的方式。使用递归可以遍历原始对象的每个属性和值,并创建新的副本。
- JSON 序列化和反序列化:可以使用 JSON.stringify() 方法将原始对象序列化为 JSON 字符串,然后使用 JSON.parse() 方法将 JSON 字符串反序列化为新的对象。
- 第三方库:可以使用像 Lodash 这样的第三方库来实现深拷贝。
浅拷贝的实现方式
- 对象赋值:可以使用
=
运算符将原始对象赋值给新的对象。 - Object.assign() 方法:可以使用 Object.assign() 方法将原始对象的属性和值复制到新的对象。
- 扩展运算符:可以使用扩展运算符 (...) 将原始对象的属性和值复制到新的对象。
深浅拷贝的适用场景
- 需要修改对象副本而不影响原始对象时,应使用深拷贝。例如,在表单编辑场景中,需要对表单数据进行深拷贝,以便在编辑过程中不会影响原始数据。
- 不需要修改对象副本时,可以使用浅拷贝。例如,在数据传输场景中,可以使用浅拷贝来传输数据,以便节省资源。
以下表格总结了深浅拷贝的主要区别:
特性 | 深拷贝 | 浅拷贝 |
---|---|---|
复制方式 | 创建新的对象并复制所有属性和值 | 创建新的对象并复制引用 |
嵌套对象 | 也会被复制 | 不会被复制 |
适用场景 | 需要修改对象副本而不影响原始对象 | 不需要修改对象副本 |
示例
JavaScript
// 深拷贝
const originalObject = {
name: "John Doe",
age: 30,
address: {
street: "123 Main Street",
city: "New York",
state: "NY",
zip: "10001",
},
};
const deepCopy = JSON.parse(JSON.stringify(originalObject));
deepCopy.name = "Jane Doe";
deepCopy.address.city = "Los Angeles";
console.log(originalObject); // { name: "John Doe", age: 30, address: { street: "123 Main Street", city: "New York", state: "NY", zip: "10001" } }
console.log(deepCopy); // { name: "Jane Doe", age: 30, address: { street: "123 Main Street", city: "Los Angeles", state: "NY", zip: "10001" } }
// 浅拷贝
const shallowCopy = Object.assign({}, originalObject);
shallowCopy.name = "Jane Doe";
shallowCopy.address.city = "Los Angeles";
console.log(originalObject); // { name: "Jane Doe", age: 30, address: { street: "123 Main Street", city: "Los Angeles", state: "NY", zip: "10001" } }
console.log(shallowCopy); // { name: "Jane Doe", age: 30, address: { street: "123 Main Street", city: "Los Angeles", state: "NY", zip: "10001" } }
深度拷贝的其它实现方法
1. 使用 ES6 的扩展运算符 (...)
JavaScript
const originalObject = {
name: "John Doe",
age: 30,
address: {
street: "123 Main Street",
city: "New York",
state: "NY",
zip: "10001",
},
};
const deepCopy = {...originalObject};
deepCopy.name = "Jane Doe";
deepCopy.address.city = "Los Angeles";
console.log(originalObject); // { name: "John Doe", age: 30, address: { street: "123 Main Street", city: "New York", state: "NY", zip: "10001" } }
console.log(deepCopy); // { name: "Jane Doe", age: 30, address: { street: "123 Main Street", city: "Los Angeles", state: "NY", zip: "10001" } }
2. 使用 Object.create() 方法
JavaScript
const originalObject = {
name: "John Doe",
age: 30,
address: {
street: "123 Main Street",
city: "New York",
state: "NY",
zip: "10001",
},
};
const deepCopy = Object.create(originalObject);
deepCopy.name = "Jane Doe";
deepCopy.address.city = "Los Angeles";
console.log(originalObject); // { name: "John Doe", age: 30, address: { street: "123 Main Street", city: "New York", state: "NY", zip: "10001" } }
console.log(deepCopy); // { name: "Jane Doe", age: 30, address: { street: "123 Main Street", city: "Los Angeles", state: "NY", zip: "10001" } }
3. 使用 Lodash 库
JavaScript
const originalObject = {
name: "John Doe",
age: 30,
address: {
street: "123 Main Street",
city: "New York",
state: "NY",
zip: "10001",
},
};
const deepCopy = _.cloneDeep(originalObject);
deepCopy.name = "Jane Doe";
deepCopy.address.city = "Los Angeles";
console.log(originalObject); // { name: "John Doe", age: 30, address: { street: "123 Main Street", city: "New York", state: "NY", zip: "10001" } }
console.log(deepCopy); // { name: "Jane Doe", age: 30, address: { street: "123 Main Street", city: "Los Angeles", state: "NY", zip: "10001" } }
每种方法都有其优缺点,应根据具体情况选择合适的方法。
以下是一些比较:
方法 | 优点 | 缺点 |
---|---|---|
递归 | 通用性强 | 效率低,容易造成栈溢出 |
JSON 序列化和反序列化 | 效率高 | 不支持循环引用 |
第三方库 | 方便易用 | 需要引入第三方库 |
ES6 扩展运算符 | 简洁易用 | 不支持 Symbol 类型 |
Object.create() 方法 | 效率高 | 不支持 Symbol 类型 |
Lodash 库 | 功能强大 | 需要引入第三方库 |