• js实现深拷贝的几种方式



    在JavaScript中,实现深拷贝的方式有以下几种:

    1. 手动递归拷贝

    通过递归遍历对象的属性,并逐个进行复制。例如:

    function deepCopy(obj) {
      if (typeof obj !== 'object' || obj === null) {
        return obj;
      }
    
      let copy = Array.isArray(obj) ? [] : {};
      for (let key in obj) {
        if (obj.hasOwnProperty(key)) {
          copy[key] = deepCopy(obj[key]);
        }
      }
    
      return copy;
    }
    
    let obj = { a: 1, b: { c: 2 } };
    let copy = deepCopy(obj);
    console.log(copy); // { a: 1, b: { c: 2 } }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    以上是比较简单的深拷贝,只处理了基本类型和数组、对象
    下面是个比较全面的深拷贝,考虑到了正则,日期等

    function deepCopy(obj) {
      // 如果是null或者undefined直接返回
      if (obj === null || typeof obj !== 'object') {
        return obj;
      }
      
      // 处理日期对象
      if (obj instanceof Date) {
        const copy = new Date();
        copy.setTime(obj.getTime());
        return copy;
      }
      
      // 处理正则表达式对象
      if (obj instanceof RegExp) {
        const flags = [];
        if (obj.global) flags.push('g');
        if (obj.ignoreCase) flags.push('i');
        if (obj.multiline) flags.push('m');
        return new RegExp(obj.source, flags.join(''));
      }
      
      // 处理数组
      if (Array.isArray(obj)) {
        const copy = [];
        for (let i = 0; i < obj.length; i++) {
          copy[i] = deepCopy(obj[i]);
        }
        return copy;
      }
      
      // 处理对象
      const copy = {};
      for (let key in obj) {
        if (obj.hasOwnProperty(key)) {
          copy[key] = deepCopy(obj[key]);
        }
      }
      return copy;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    示例用法:

    const obj1 = {
      name: 'John',
      age: 30,
      hobbies: ['reading', 'coding'],
      address: {
        city: 'New York',
        country: 'USA'
      },
      birthday: new Date('1990-01-01'),
      regex: /hello/g
    };
    
    const obj2 = deepCopy(obj1);
    console.log(obj2);
    
    // 修改obj2的值,不会影响到obj1
    obj2.name = 'Tom';
    obj2.hobbies.push('playing');
    obj2.address.city = 'London';
    obj2.birthday.setFullYear(1995);
    
    console.log(obj1);
    console.log(obj2);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    输出结果:

    {
      name: 'John',
      age: 30,
      hobbies: [ 'reading', 'coding' ],
      address: { city: 'New York', country: 'USA' },
      birthday: 1990-01-01T00:00:00.000Z,
      regex: /hello/g
    }
    {
      name: 'John',
      age: 30,
      hobbies: [ 'reading', 'coding' ],
      address: { city: 'New York', country: 'USA' },
      birthday: 1990-01-01T00:00:00.000Z,
      regex: /hello/g
    }
    {
      name: 'Tom',
      age: 30,
      hobbies: [ 'reading', 'coding', 'playing' ],
      address: { city: 'London', country: 'USA' },
      birthday: 1995-01-01T00:00:00.000Z,
      regex: /hello/g
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    2. JSON序列化和反序列化

    通过使用JSON.stringify()和JSON.parse()方法将对象转为字符串,再转回对象,实现深拷贝。但该方法不能处理函数、循环引用等特殊情况。例如:

    let obj = { a: 1, b: { c: 2 } };
    let copy = JSON.parse(JSON.stringify(obj));
    console.log(copy); // { a: 1, b: { c: 2 } }
    
    • 1
    • 2
    • 3

    json序列化的局限性
    使用JSON.stringify和JSON.parse进行深拷贝有以下局限性:

    1. 无法处理循环引用:如果对象中存在循环引用,则在使用JSON.stringify时会导致错误,无法完成深拷贝。

    2. 丢失特定类型信息:通过JSON.stringify和JSON.parse进行序列化和反序列化会导致一些特定类型的信息丢失,例如日期对象被转换成字符串,正则表达式对象被转换成空对象。

    3. 无法拷贝函数和原型链:JSON.stringify和JSON.parse只能处理JSON支持的数据类型,无法拷贝函数和原型链。

    4. 对象中存在undefined值时会被忽略:JSON.stringify会将对象中的undefined值转换为null,而JSON.parse会忽略null值,导致无法还原原始的undefined值。

    5. 性能较低:相比其他深拷贝方法,使用JSON.stringify和JSON.parse进行深拷贝的性能较低,尤其是在处理大型对象或嵌套深的对象时,会消耗较多的时间和内存。

    综上所述,尽管JSON.stringify和JSON.parse可以完成一些简单对象的深拷贝,但在处理复杂或特殊类型的对象时存在一定的局限性。更好的方法是使用其他深拷贝技术,如递归复制、Object.assign()或第三方库(如lodash的cloneDeep方法),以满足更多复杂的深拷贝需求。

    3. Object.assign()方法

    此方法可以将多个对象的属性合并到一个目标对象中,从而实现深拷贝。但对于嵌套的对象或数组,仍然是浅拷贝。例如:

    let obj = { a: 1, b: { c: 2 } };
    let copy = Object.assign({}, obj);
    console.log(copy); // { a: 1, b: { c: 2 } }
    
    • 1
    • 2
    • 3

    4. 使用第三方库

    如Lodash中的cloneDeep()方法,它提供了更强大和灵活的深拷贝功能。例如:

    const _ = require('lodash');
    
    let obj = { a: 1, b: { c: 2 } };
    let copy = _.cloneDeep(obj);
    console.log(copy); // { a: 1, b: { c: 2 } }
    
    • 1
    • 2
    • 3
    • 4
    • 5
  • 相关阅读:
    Win11dll文件缺失怎么修复?Win11系统dll文件丢失的解决方法
    Qt(day3)
    Feign常用的注解、Http请求调用
    蓄电池与超级电容混合储能并网逆变系统Simulink仿真
    如何双开或多开skype
    2-2: HyperText Transfer Protocol超文本传输协议及HTTP发展历程
    2023Android白名单保活(后台定位)分享
    linux+ndk把jni制作成so库供apk使用(基础)
    Python学习第8天:List
    2020-2023小样本学习(FSL)顶会论文及开源代码合集(已分类整理)
  • 原文地址:https://blog.csdn.net/jieyucx/article/details/134059533