浅拷贝与深拷贝的区别?
1. 什么是浅拷贝与深拷贝
js 的深拷贝与浅拷贝是两种不同的对象复制方式,它们之间的核心区别是如何处理对象内部包含的复杂结构,尤其是嵌套的对象和数组
1.1. 浅拷贝
将源始对象的属性复制给新对象,如果是基本数据类型拷贝的是这个基本数据类型的值;如果是引用类型拷贝的是这个内存地址的引用。因此源始对象和复制对象共享同一个引用地址,这也意味着属性的修改会影响源对象。
1.2. 深拷贝
会递归地复制源始对象及其所有嵌套的子对象,从而使源对象与拷贝对象在内存中是完全独立的,对任何属性修改都不会影响源对象。
2. 实现方法
2.1. 浅拷贝的实现
2.1.1. Object.assign()
这是 ES6 中用于将所有可枚举属性的值从一个或多个源对象复制到目标对象的方法,它返回目标对象。
const original = { a: 1, b: { c: 2 } };
const shallowCopy = Object.assign({}, original);shallowCopy.a = 3; // 不会影响 original.a
shallowCopy.b.c = 4; // 会影响 original.b.c
2.1.2. 展开语法(...)
同样是ES6的特性,展开语法可以简洁地实现对象的浅拷贝。
const original = { a: 1, b: { c: 2 } };
const shallowCopy = { ...original };
2.1.3. 数组方法
对于数组可以使用 Array.prototype.slice()
、Array.prototype.concat()
或 Array.from()
等方法实现浅拷贝。
2.2. 深拷贝的实现
2.2.1. JSON.parse(JSON.stringify(object))
这是一种简单快捷的深拷贝方法,但存在一些局限性。
优点: 实现简单,易于理解和使用。
缺点:
- 会忽略值为 undefined、Symbol 的属性和函数。
- 无法处理循环引用的对象,会抛出错误。
- 会丢失对象的构造函数信息,所有对象都会变成纯粹的 Object。
- 无法正确处理像 BigInt 这样的数据类型。
2.2.2. structuredClone()
这是一个较新的Web API,专门用于深拷贝,它能解决 JSON 方法的许多不足。
优点: 支持多种JavaScript类型,并且能够处理循环引用。
缺点: 它是一个浏览器特性,而非JavaScript语言本身的一部分,需要注意环境兼容性。[12] 同时,它仍然无法复制函数和原型链上的属性。
2.2.3. 递归手动实现
编写一个递归函数是实现深拷贝的根本方法。
function deepClone(obj, hash = new WeakMap()) {if (obj === null || typeof obj !== 'object') return obj;if (hash.has(obj)) return hash.get(obj);let cloneObj = Array.isArray(obj) ? [] : {};hash.set(obj, cloneObj);for (let key in obj) {if (Object.prototype.hasOwnProperty.call(obj, key)) {cloneObj[key] = deepClone(obj[key], hash);}}return cloneObj;
}
2.2.4. 第三方库
Lodash 的 _.cloneDeep() 方法。
3. 总结
浅拷贝只负责最外层的引用,深拷贝保证所有层级数据能被独立复制实现原始对象和复制对象的完全隔离,Object.assign()
、展开语法、实现浅拷贝;JSON.parse(JSON.stringify(object))、递归实现深拷贝