浅拷贝和深拷贝你搞懂了吗

在编程中,我们经常需要复制数据。然而,并不是所有的复制操作都是一样的。根据复制的深度,我们可以将复制分为浅拷贝(Shallow Copy)深拷贝(Deep Copy)。这两种方式有着本质的区别,本文将深入探讨浅拷贝和深拷贝的概念、实现方式以及使用场景。


1. 什么是浅拷贝?

1.1 定义

浅拷贝是指创建一个新对象,并将原对象的属性值复制到新对象中。如果属性是基本类型(如numberstringboolean),则直接复制值;如果属性是引用类型(如objectarray),则复制引用地址。

换句话说,浅拷贝只复制对象的第一层属性,而不会递归复制嵌套的对象。

1.2 实现方式

在JavaScript中,浅拷贝可以通过多种方式实现:

1.2.1 使用Object.assign

1
2
3
4
const obj = { a: 1, b: { c: 2 } };
const shallowCopy = Object.assign({}, obj);

console.log(shallowCopy); // { a: 1, b: { c: 2 } }

1.2.2 使用展开运算符(...

1
2
3
4
const obj = { a: 1, b: { c: 2 } };
const shallowCopy = { ...obj };

console.log(shallowCopy); // { a: 1, b: { c: 2 } }

1.2.3 数组的浅拷贝

1
2
3
4
const arr = [1, 2, { a: 3 }];
const shallowCopy = arr.slice();

console.log(shallowCopy); // [1, 2, { a: 3 }]

1.3 浅拷贝的特点

  • 复制引用:如果属性是引用类型,浅拷贝只会复制引用地址,新旧对象共享同一块内存。
  • 修改影响:修改浅拷贝对象中的引用类型属性,会影响原对象。
1
2
3
4
5
6
const obj = { a: 1, b: { c: 2 } };
const shallowCopy = { ...obj };

shallowCopy.b.c = 3;

console.log(obj.b.c); // 3(原对象也被修改)

2. 什么是深拷贝?

2.1 定义

深拷贝是指创建一个新对象,并递归地复制原对象的所有属性,包括嵌套的对象和数组。深拷贝会完全复制对象的结构和数据,新旧对象不共享同一块内存。

2.2 实现方式

在JavaScript中,深拷贝可以通过以下方式实现:

2.2.1 使用JSON.parseJSON.stringify

1
2
3
4
const obj = { a: 1, b: { c: 2 } };
const deepCopy = JSON.parse(JSON.stringify(obj));

console.log(deepCopy); // { a: 1, b: { c: 2 } }

注意:这种方式无法复制函数、undefinedSymbol等特殊类型。

2.2.2 使用递归函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function deepClone(obj) {
if (obj === null || typeof obj !== 'object') {
return obj;
}

const clone = Array.isArray(obj) ? [] : {};

for (let key in obj) {
if (obj.hasOwnProperty(key)) {
clone[key] = deepClone(obj[key]);
}
}

return clone;
}

const obj = { a: 1, b: { c: 2 } };
const deepCopy = deepClone(obj);

console.log(deepCopy); // { a: 1, b: { c: 2 } }

2.2.3 使用第三方库(如Lodash)

1
2
3
4
5
6
const _ = require('lodash');

const obj = { a: 1, b: { c: 2 } };
const deepCopy = _.cloneDeep(obj);

console.log(deepCopy); // { a: 1, b: { c: 2 } }

2.3 深拷贝的特点

  • 完全复制:深拷贝会递归复制所有嵌套的对象和数组,新旧对象互不影响。
  • 修改不影响:修改深拷贝对象中的属性,不会影响原对象。
1
2
3
4
5
6
const obj = { a: 1, b: { c: 2 } };
const deepCopy = JSON.parse(JSON.stringify(obj));

deepCopy.b.c = 3;

console.log(obj.b.c); // 2(原对象未被修改)

3. 浅拷贝 vs 深拷贝

特性 浅拷贝 深拷贝
复制深度 只复制第一层属性 递归复制所有嵌套属性
引用类型 复制引用地址,新旧对象共享内存 完全复制数据,新旧对象互不影响
性能 较高(只复制一层) 较低(递归复制所有层级)
适用场景 简单对象,无需复制嵌套结构 复杂对象,需要完全独立的副本
实现方式 Object.assign、展开运算符、slice JSON.parse(JSON.stringify)、递归函数等

4. 使用场景

4.1 浅拷贝的使用场景

  • 简单对象的复制:当对象结构简单,且没有嵌套引用类型时,浅拷贝是高效的选择。
  • 性能优先的场景:如果不需要复制嵌套结构,浅拷贝可以节省内存和计算资源。

4.2 深拷贝的使用场景

  • 复杂对象的复制:当对象结构复杂,且包含嵌套引用类型时,深拷贝是必要的。
  • 数据隔离的场景:如果希望新旧对象完全独立,互不影响,必须使用深拷贝。

5. 使用建议

在实际开发中,我们需要根据具体需求选择合适的复制方式。如果你不确定该用哪种方式,记住一个简单的原则:如果对象包含嵌套引用类型,且需要完全独立的副本,就使用深拷贝;否则,浅拷贝通常就足够了。