在编程中,我们经常需要复制数据。然而,并不是所有的复制操作都是一样的。根据复制的深度,我们可以将复制分为浅拷贝(Shallow Copy)和深拷贝(Deep Copy)。这两种方式有着本质的区别,本文将深入探讨浅拷贝和深拷贝的概念、实现方式以及使用场景。
1. 什么是浅拷贝?
1.1 定义
浅拷贝是指创建一个新对象,并将原对象的属性值复制到新对象中。如果属性是基本类型(如number、string、boolean),则直接复制值;如果属性是引用类型(如object、array),则复制引用地址。
换句话说,浅拷贝只复制对象的第一层属性,而不会递归复制嵌套的对象。
1.2 实现方式
在JavaScript中,浅拷贝可以通过多种方式实现:
1.2.1 使用Object.assign
| 12
 3
 4
 
 | const obj = { a: 1, b: { c: 2 } };const shallowCopy = Object.assign({}, obj);
 
 console.log(shallowCopy);
 
 | 
1.2.2 使用展开运算符(...)
| 12
 3
 4
 
 | const obj = { a: 1, b: { c: 2 } };const shallowCopy = { ...obj };
 
 console.log(shallowCopy);
 
 | 
1.2.3 数组的浅拷贝
| 12
 3
 4
 
 | const arr = [1, 2, { a: 3 }];const shallowCopy = arr.slice();
 
 console.log(shallowCopy);
 
 | 
1.3 浅拷贝的特点
- 复制引用:如果属性是引用类型,浅拷贝只会复制引用地址,新旧对象共享同一块内存。
- 修改影响:修改浅拷贝对象中的引用类型属性,会影响原对象。
| 12
 3
 4
 5
 6
 
 | const obj = { a: 1, b: { c: 2 } };const shallowCopy = { ...obj };
 
 shallowCopy.b.c = 3;
 
 console.log(obj.b.c);
 
 | 
2. 什么是深拷贝?
2.1 定义
深拷贝是指创建一个新对象,并递归地复制原对象的所有属性,包括嵌套的对象和数组。深拷贝会完全复制对象的结构和数据,新旧对象不共享同一块内存。
2.2 实现方式
在JavaScript中,深拷贝可以通过以下方式实现:
2.2.1 使用JSON.parse和JSON.stringify
| 12
 3
 4
 
 | const obj = { a: 1, b: { c: 2 } };const deepCopy = JSON.parse(JSON.stringify(obj));
 
 console.log(deepCopy);
 
 | 
注意:这种方式无法复制函数、undefined、Symbol等特殊类型。
2.2.2 使用递归函数
| 12
 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);
 
 | 
2.2.3 使用第三方库(如Lodash)
| 12
 3
 4
 5
 6
 
 | const _ = require('lodash');
 const obj = { a: 1, b: { c: 2 } };
 const deepCopy = _.cloneDeep(obj);
 
 console.log(deepCopy);
 
 | 
2.3 深拷贝的特点
- 完全复制:深拷贝会递归复制所有嵌套的对象和数组,新旧对象互不影响。
- 修改不影响:修改深拷贝对象中的属性,不会影响原对象。
| 12
 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);
 
 | 
3. 浅拷贝 vs 深拷贝
| 特性 | 浅拷贝 | 深拷贝 | 
| 复制深度 | 只复制第一层属性 | 递归复制所有嵌套属性 | 
| 引用类型 | 复制引用地址,新旧对象共享内存 | 完全复制数据,新旧对象互不影响 | 
| 性能 | 较高(只复制一层) | 较低(递归复制所有层级) | 
| 适用场景 | 简单对象,无需复制嵌套结构 | 复杂对象,需要完全独立的副本 | 
| 实现方式 | Object.assign、展开运算符、slice等 | JSON.parse(JSON.stringify)、递归函数等 | 
4. 使用场景
4.1 浅拷贝的使用场景
- 简单对象的复制:当对象结构简单,且没有嵌套引用类型时,浅拷贝是高效的选择。
- 性能优先的场景:如果不需要复制嵌套结构,浅拷贝可以节省内存和计算资源。
4.2 深拷贝的使用场景
- 复杂对象的复制:当对象结构复杂,且包含嵌套引用类型时,深拷贝是必要的。
- 数据隔离的场景:如果希望新旧对象完全独立,互不影响,必须使用深拷贝。
5. 使用建议
在实际开发中,我们需要根据具体需求选择合适的复制方式。如果你不确定该用哪种方式,记住一个简单的原则:如果对象包含嵌套引用类型,且需要完全独立的副本,就使用深拷贝;否则,浅拷贝通常就足够了。