• javascript深浅拷贝


    前置

    let a = {
        age: 1
    }
    let b = a
    a.age = 2
    console.log(b.age) // 2
    

    从上述例子中我们可以发现,如果给一个变量赋值一个对象,那么两者的值会是同一个引用,其中一方改变,另一方也会相应改变。
    通常在开发中我们不希望出现这样的问题,我们可以使用浅拷贝来解决这个问题。

    浅拷贝

    首先可以通过 Object.assign 来解决这个问题。

    let a = {
        age: 1
    }
    let b = Object.assign({}, a)
    a.age = 2
    console.log(b.age) // 1
    

    通过展开运算符(…)来解决

    let a = {
        age: 1
    }
    let b = {...a}
    a.age = 2
    console.log(b.age) // 1
    

    通常浅拷贝就能解决大部分问题了,但是当我们遇到如下情况就需要使用到深拷贝了

    let a = {
        age: 1,
        jobs: {
            first: 'FE'
        }
    }
    let b = {...a}
    a.jobs.first = 'native'
    console.log(b.jobs.first) // native
    

    浅拷贝只解决了第一层的问题,如果接下去的值中还有对象的话,那么就又回到刚开始的话题了,两者享有相同的引用。要解决这个问题,我们需要引入深拷贝

    深拷贝

    这个问题通常可以通过 JSON.parse(JSON.stringify(object)) 来解决。

    let a = {
        age: 1,
        jobs: {
            first: 'FE'
        }
    }
    let b = JSON.parse(JSON.stringify(a))
    a.jobs.first = 'native'
    console.log(b.jobs.first) // FE
    

    但是该方法也是有局限性的:

    • 会忽略 undefined
    • 会忽略 symbol
    • 不能序列化函数
    • 不能解决循环引用的对象
    let obj = {
      a: 1,
      b: {
        c: 2,
        d: 3,
      },
    }
    obj.c = obj.b
    obj.e = obj.a
    obj.b.c = obj.c
    obj.b.d = obj.b
    obj.b.e = obj.b.c
    let newObj = JSON.parse(JSON.stringify(obj))
    console.log(newObj)
    

    如果你有这么一个循环引用对象,你会发现你不能通过该方法深拷贝
    Uncaught TypeError: Converting circular structure to JSON at JSoN. stringify () at : 13: 30

    在遇到函数、 undefined 或者 symbol 的时候,该对象也不能正常的序列化

    let a = {
        age: undefined,
        sex: Symbol('male'),
        jobs: function() {},
        name: 'yck'
    }
    let b = JSON.parse(JSON.stringify(a))
    console.log(b) // {name: "yck"}
    

    你会发现在上述情况中,该方法会忽略掉函数和 undefined 。

    但是在通常情况下,复杂数据都是可以序列化的,所以这个函数可以解决大部分问题,并且该函数是内置函数中处理深拷贝性能最快的。当然如果你的数据中含有以上三种情况下,可以使用 lodash 的深拷贝函数。

    如果你所需拷贝的对象含有内置类型并且不包含函数,可以使用 MessageChannel

    function structuralClone(obj) {
      return new Promise(resolve ={
        const {port1, port2} = new MessageChannel();
        port2.onmessage = ev =resolve(ev.data);
        port1.postMessage(obj);
      });
    }
    
    var obj = {a: 1, b: {
        c: b
    }}
    // 注意该方法是异步的
    // 可以处理 undefined 和循环引用对象
    (async () ={
      const clone = await structuralClone(obj)
    })()
    

    参考资料:
    前端进阶之道

  • 相关阅读:
    Hibernate Validation注解列表
    Java_Shell多线程
    Lua读写文件
    shell导出和导入redis
    大文件读写
    Java_Hbase优化
    控制语句if
    字典(DICT)
    元组Tuple
    Session 会话
  • 原文地址:https://www.cnblogs.com/guangzan/p/11270628.html
Copyright © 2020-2023  润新知