深拷贝会递归复制对象所有嵌套属性,确保新旧对象完全独立,而浅拷贝仅复制引用,导致修改相互影响;常用深拷贝方法包括JSON.parse(JSON.stringify(obj))、递归函数处理循环引用和特殊对象,或使用Lodash的_.cloneDeep()及现代API structuredClone()。

浅拷贝仅仅是复制了对象或数组的引用,这意味着新旧变量指向的是内存中的同一块数据,当其中一个修改了内部的复杂类型(比如另一个对象或数组)时,另一个也会随之改变。而深拷贝则不然,它会递归地复制所有嵌套的属性,确保新旧对象在内存中拥有完全独立的存储空间,彼此互不影响。实现深拷贝,通常需要根据对象的结构,逐层、逐属性地进行复制,尤其要关注那些引用类型的数据。
理解深拷贝与浅拷贝的核心在于它们对“引用”的处理方式。浅拷贝在遇到对象内部的引用类型属性时,只会复制这个引用本身,而不是引用所指向的实际数据。这就好比你复制了一个文件的快捷方式,而不是文件本身。你通过快捷方式修改了文件内容,原文件自然也变了。深拷贝则不同,它会深入到每一个引用类型属性的内部,将其指向的数据也完整地复制一份,直到所有数据都是原始类型(如数字、字符串、布尔值)为止。这就像你把整个文件都复制了一遍,新旧文件完全独立。
要实现深拷贝,在JavaScript中,最简单粗暴但也最常用的方法是利用
JSON.parse(JSON.stringify(obj))
undefined
Date
RegExp
说实话,我个人在开发中就遇到过好几次因为没搞清楚浅拷贝而引发的“血案”。最典型的场景就是当你从一个配置对象中取出一个子对象,然后直接修改它,结果发现原始的配置对象也跟着变了,这在调试时简直是灾难。
想象一下,你有一个用户设置对象,里面包含一个
theme
Object.assign()
{...userSettings}userSettings
theme
copiedSettings.theme.primaryColor = 'blue'
userSettings.theme.primaryColor
blue
这种行为模式,尤其在处理数组嵌套对象时,更让人头疼。比如一个包含多个商品对象的购物车数组,如果你浅拷贝了这个数组,然后修改了其中一个商品的某个属性,那么原始购物车数组里的那个商品也会被修改。这不仅影响了数据的纯洁性,也让程序的行为变得难以预测和维护。理解浅拷贝的本质,是避免这些潜在风险的第一步。
实现深拷贝,方法多种多样,选择哪种取决于你的具体需求和要处理的数据复杂性。
最简单直接的,正如前面提到的,是
JSON.parse(JSON.stringify(obj))
undefined
Symbol
BigInt
Date
RegExp
当
JSON
function deepClone(obj, hash = new WeakMap()) {
if (obj === null || typeof obj !== 'object') {
return obj;
}
// 处理循环引用
if (hash.has(obj)) {
return hash.get(obj);
}
let cloneObj;
// 处理日期对象
if (obj instanceof Date) {
cloneObj = new Date(obj);
}
// 处理正则表达式
else if (obj instanceof RegExp) {
cloneObj = new RegExp(obj);
}
// 处理Map、Set等其他特殊对象
// else if (obj instanceof Map) { ... }
// else if (obj instanceof Set) { ... }
// ...
else {
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;
}这个递归函数需要考虑很多细节,比如如何处理
Date
RegExp
Map
Set
WeakMap
对于更健壮和全面的深拷贝,很多时候我们会选择使用成熟的第三方库,比如Lodash的
_.cloneDeep()
深拷贝并非没有代价,尤其是在处理大型或深度嵌套的对象时,其性能开销是需要考虑的。
JSON.parse(JSON.stringify(obj))
循环引用是一个深拷贝的经典难题。当一个对象A引用了对象B,而对象B又引用了对象A时,就形成了循环引用。如果深拷贝函数没有处理机制,它会无限递归下去,最终导致栈溢出。前面提到的
WeakMap
Map
特殊对象的处理也是深拷贝的另一个难点。除了前面提到的
Date
RegExp
Map
Set
Promise
Error
Map
Set
structuredClone()
Date
RegExp
Map
Set
ArrayBuffer
JSON
以上就是深拷贝与浅拷贝的区别是什么?如何实现深拷贝?的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号