深拷贝数组或者对象和JSON.parse(JSON.stringify(obj))

function deepClone(obj = {}) {
    if (typeof obj !== 'object' || obj == null) {
        return obj;
    }
    let result;
    if (obj instanceof Array) {
        result = [];
    } else {
        result = {};
    }
    for (let key in obj) {
      //看是否是自身属性
      if(obj.hasOwnProperty(key)){
        result[key] = deepClone(obj[key]);
      }
       
    }
    return result;
}

这行代码的运行过程,就是利用 JSON.stringify 将js对象序列化(JSON字符串),再使用JSON.parse来反序列化(还原)js对象;序列化的作用是存储和传输。(对象本身存储的是一个地址映射,如果断电,对象将不存在,所以要将对象的内容转换成字符串的形式再保存在磁盘上)

不过,这种实现深拷贝的方法有局限性,它只适用于一般数据的拷贝(对象、数组),有以下情况需要注意:

  1. 如果json里面有时间对象,则序列化结果:时间对象=>字符串的形式;

  1. 如果json里有RegExp、Error对象,则序列化的结果将只得到空对象 RegExp、Error => {};

  1. 如果json里有 function,undefined,则序列化的结果会把 function,undefined 丢失;

  1. 如果json里有NaN、Infinity和-Infinity,则序列化的结果会变成null;

  1. 如果json里有对象是由构造函数生成的,则序列化的结果会丢弃对象的 constructor;

  1. 如果对象中存在循环引用的情况也无法实现深拷贝

如果拷贝的对象不涉及上面的情况,可以使用 JSON.parse(JSON.stringify(obj)) 实现深拷贝。

### 前端 JavaScript 深拷贝对象使用 `JSON.parse` `JSON.stringify` 方法的问题与解决方案 #### 问题描述 在前端开发中,有时需要创建对象的副本而不影响原始对象。对于复杂的数据结构,简单的赋值操作只会复制引用而不是实际的对象内容。为了实现真正的深拷贝,开发者经常采用 `JSON.parse(JSON.stringify(object))` 这种方式[^4]。 然而这种方法并非万能,在某些情况下可能会遇到意想不到的行为: - **循环引用**:当对象内部含有指向自身的属性时,调用 `stringify()` 会抛出错误。 - **函数丢失**:由于 JSON 只支持特定几种数据类型的表示法,像 Function 类型这样的特殊成员会被忽略掉[^2]。 - **原型链破坏**:新生成的对象不会继承原有实例的方法或特性,因为它们只包含了可枚举自有属性及其值。 - **Date 对象及其他内置类**:日期其他一些原生构造器产生的实体可能无法被正确恢复为相同类型的新实例[^3]。 #### 解决方案 针对上述提到的各种情况,这里给出几个改进建议以及替代方案: ##### 处理循环引用 可以通过自定义 replacer 函数来检测并跳过那些形成环路的部分,从而避免无限递归导致程序崩溃。不过更推荐的做法是寻找专门设计用来处理这种情况的库,比如 lodash 或者 structuredClone API (现代浏览器环境)。 ##### 保留函数构造器信息 如果确实有必要保持这些细节不变的话,则不得不放弃纯粹依赖于标准库的方式转而编写更加复杂的逻辑去遍历整个目标树形结构逐项克隆每一个节点的同时记录下必要的元数据以便后续重建完整的功能集。这显然增加了不少工作量同时也降低了代码通用性易读性所以除非绝对必要否则应尽量简化需求范围内的要求仅限于基础数值/字符串等简单项目即可满足大部分应用场景下的预期效果[^5]。 ##### 维护原型关系 考虑到大多数时候我们并不关心副件是否完全一致而是仅仅希望得到一份独立存在的镜像版本那么这个问题实际上是可以接受一定程度上的折衷即允许最终产物失去部分原本具有的行为特征只要不影响主要业务流程运转就行。当然如果有严格的要求要维持原有的方法列表也可以考虑手动重新挂载所需的功能模块到新的容器上去。 ```javascript function deepCopyWithPrototypes(source) { const copy = Object.create(Object.getPrototypeOf(source)); for (let key in source) { if (source.hasOwnProperty(key)) { copy[key] = typeof source[key] === 'object' && source[key] !== null ? deepCopyWithPrototypes(source[key]) : source[key]; } } return copy; } ``` ##### 特殊类型的支持 对于 Date 等特殊情况可以在序列化之前先做预处理将其转化为易于识别的形式然后再通过相应的逆向转换步骤确保能够准确无误地还原回原来的形态。 ```javascript const obj = { date: new Date('2023-01-01') }; // 序列化前准备 obj.date = obj.date.toISOString(); const jsonString = JSON.stringify(obj); console.log(jsonString); // 输出:"{"date":"2023-01-01T00:00:00.000Z"}" // 反序列化后修复 const parsedObj = JSON.parse(jsonString, function(k, v){ if (k === "date") return new Date(v); return v; }); console.log(parsedObj.date instanceof Date); // true ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值