深拷贝方法

深拷贝两种方法解析
  • 第一种方法(最优):
function deepCopy(p, c) {
    var c = c || {};
    for (var i in p) {
        if(!p.hasOwnProperty(i)){
            continue;
        }
        if (typeof p[i] === 'object') {
            c[i] = (p[i].constructor === Array) ? [] : {};
            deepCopy(p[i], c[i]);
        } else {
            c[i] = p[i];
        }
    }
    return c;
}
  • 第二种方法(缺点:不能拷贝对象内部function):
JSON.parse(JSON.stringify())

 

 

<think>我们正在回答用户关于JavaScript深拷贝方法的问题。根据引用,我们有几种不同的方法可以实现深拷贝。首先,深拷贝是指创建一个新对象,并递归地复制原始对象的所有属性,使得新对象和原始对象完全独立,修改新对象不会影响原始对象。根据引用,我们可以总结以下几种深拷贝的实现方法:1.**使用JSON序列化和反序列化**(引用[1]和引用[3]提到):这种方法简单,但有其局限性:不能复制函数、undefined、Symbol值,以及一些特殊的对象(如Date、RegExp等)在序列化后会变成字符串,反序列化后无法还原。2.**递归实现**(引用[2]和引用[4]提到):通过递归遍历对象的每个属性,针对不同的类型(数组、对象)进行复制。这种方法可以处理嵌套对象和数组,但同样需要特殊处理一些内置对象(如Date、RegExp等)和循环引用。3.**使用MessageChannel**(引用[3]提到):这是一种利用异步通信API实现深拷贝方法,可以处理一些JSON无法处理的情况(如undefined和函数),但同样不能处理函数和循环引用,而且它是异步的。由于用户没有特殊要求,我们将重点介绍前两种方法,并给出代码示例。###方法1:使用JSON序列化和反序列化```javascriptfunctiondeepClone(obj){returnJSON.parse(JSON.stringify(obj));}```**注意**:这种方法虽然简单,但有以下缺点:-忽略函数属性(因为JSON不支持函数)-忽略undefined和Symbol值-忽略对象的constructor,即原对象的原型链会丢失-不能处理循环引用(会报错)-特殊对象如Date会变成字符串,RegExp会变成空对象###方法2:递归实现(基础版)下面是一个递归实现的深拷贝函数,可以处理对象和数组的嵌套,但不处理特殊对象和循环引用。```javascriptfunctiondeepClone(obj){//如果是基本类型或null,直接返回if(obj===null||typeofobj!=='object'){returnobj;}//处理数组if(Array.isArray(obj)){constcloneArr=[];for(leti=0;i<obj.length;i++){cloneArr[i]=deepClone(obj[i]);}returncloneArr;}//处理普通对象constcloneObj={};for(letkeyinobj){if(obj.hasOwnProperty(key)){cloneObj[key]=deepClone(obj[key]);}}returncloneObj;}```###方法3:递归实现(增强版)为了处理更多的内置对象和循环引用,我们可以增强递归实现:```javascriptfunctiondeepClone(obj,hash=newWeakMap()){//如果是基本类型或null,直接返回if(obj===null||typeofobj!=='object'){returnobj;}//如果已存在循环引用,则直接返回存储的值if(hash.has(obj)){returnhash.get(obj);}//处理Date对象if(objinstanceofDate){constcopy=newDate(obj);hash.set(obj,copy);returncopy;}//处理RegExp对象if(objinstanceofRegExp){constcopy=newRegExp(obj.source,obj.flags);hash.set(obj,copy);returncopy;}//处理数组if(Array.isArray(obj)){constcloneArr=[];hash.set(obj,cloneArr);for(leti=0;i<obj.length;i++){cloneArr[i]=deepClone(obj[i],hash);}returncloneArr;}//处理普通对象constcloneObj=Object.create(Object.getPrototypeOf(obj));hash.set(obj,cloneObj);for(letkeyinobj){if(obj.hasOwnProperty(key)){cloneObj[key]=deepClone(obj[key],hash);}}returncloneObj;}```这个增强版函数通过使用WeakMap来存储已经拷贝过的对象,解决了循环引用的问题,并增加了对Date和RegExp对象的支持。但是,函数属性仍然被直接返回(因为函数是基本类型?不,函数是对象,但这里我们按基本类型处理?不对,函数在JavaScript中是对象,但通常我们不希望复制函数,因为函数是共享的)。因此,这个函数不会复制函数,但会复制其他可枚举属性。###其他方法除了上述方法,还可以使用第三方库(如lodash的`_.cloneDeep`)来实现深拷贝,这些库通常处理了更多边界情况。###总结-对于简单对象(没有函数、循环引用和特殊对象),可以使用`JSON.parse(JSON.stringify(obj))`。-对于复杂对象,建议使用递归实现,并考虑循环引用和特殊对象。-在实际项目中,使用成熟的库(如lodash)是更可靠的选择。§§相关问题§§1.深拷贝和浅拷贝有什么区别?2.如何实现一个处理循环引用的深拷贝函数?3.使用JSON方法实现深拷贝有什么局限性?4.在JavaScript中,如何复制一个包含函数的对象?5.第三方库(如lodash)是如何实现深拷贝的?</think>### JavaScript 深拷贝实现方法详解 在 JavaScript 中实现深拷贝的核心是**创建独立的内存空间**,递归复制所有嵌套属性。以下是几种常用方法及原理分析: #### 方法1:JSON 序列化法(简单场景) ```javascript function deepClone(obj) { return JSON.parse(JSON.stringify(obj)); } ``` **原理**: 通过 `JSON.stringify()` 将对象转为字符串,再用 `JSON.parse()` 重建新对象。 ✅ 优点:代码简洁 ❌ 缺点: - 无法复制 `函数`、`undefined`、`Symbol` 类型 - 会丢失 `Date` 对象(转为字符串) - 无法处理 `循环引用`(如 `obj.self = obj`) #### 方法2:递归实现(基础版) ```javascript function deepClone(obj) { if (obj === null || typeof obj !== 'object') { return obj; // 基本类型直接返回 } const cloneObj = Array.isArray(obj) ? [] : {}; for (let key in obj) { if (obj.hasOwnProperty(key)) { cloneObj[key] = deepClone(obj[key]); // 递归复制嵌套属性 } } return cloneObj; } ``` **适用场景**: 处理普通对象和数组的嵌套结构,如: ```javascript const original = { a: 1, b: { c: [2, 3] } }; const cloned = deepClone(original); console.log(cloned.b.c === original.b.c); // false(深拷贝成功) ``` #### 方法3:增强递归版(支持特殊类型) ```javascript function deepClone(obj, hash = new WeakMap()) { if (obj === null) return null; if (typeof obj !== 'object') return obj; if (obj instanceof Date) return new Date(obj); // 处理Date if (obj instanceof RegExp) return new RegExp(obj); // 处理正则 if (hash.has(obj)) return hash.get(obj); // 解决循环引用 const cloneObj = new obj.constructor(); hash.set(obj, cloneObj); for (let key in obj) { if (obj.hasOwnProperty(key)) { cloneObj[key] = deepClone(obj[key], hash); } } return cloneObj; } ``` ✅ 增强功能: 1. 支持 `Date`、`RegExp` 等内置对象 2. 通过 `WeakMap` 解决循环引用问题 3. 保持原型链 (`new obj.constructor()`) #### 方法4:MessageChannel API(异步深拷贝) ```javascript function deepClone(obj) { return new Promise(resolve => { const { port1, port2 } = new MessageChannel(); port2.onmessage = ev => resolve(ev.data); port1.postMessage(obj); }); } // 使用示例 deepClone(obj).then(clone => { console.log(clone); }); ``` **特点**: - 可复制 `undefined` 和函数(但函数会丢失原型链) - 异步操作,适合复杂对象 - 仍无法解决循环引用 #### 方法对比表 | 方法 | 函数支持 | 循环引用 | 特殊类型 | 性能 | |--------------------|----------|----------|----------|--------| | JSON法 | ❌ | ❌ | ❌ | ⭐⭐⭐⭐ | | 基础递归 | ✅ | ❌ | ❌ | ⭐⭐⭐ | | 增强递归 | ✅ | ✅ | ✅ | ⭐⭐ | | MessageChannel | ✅ | ❌ | ✅ | ⭐ | #### 最佳实践建议 1. 简单对象 → **JSON法**(最快) 2. 含函数/嵌套对象 → **增强递归版** 3. 超大对象 → 考虑 **lodash.cloneDeep**(库函数优化过性能) 4. 避免深拷贝场景 → 使用不可变数据结构(如Immer.js) > 示例库实现参考:lodash 的 [_.cloneDeep](https://lodash.com/docs/4.17.15#cloneDeep) 使用组合式类型检测和递归,支持超过20种特殊对象类型[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值