zoukankan      html  css  js  c++  java
  • 前端对象的深浅拷贝以及处理复杂数据对象时注意点

    关于前端对象的引用:

    一:

    如果处理复杂的数据结构:如果引用的数据结构只是值得传递时;不会出身问题;

    但是一旦出现引用对象是一个对象;必须要重新创建对象;进行引用:

    {

    "name":'张华',

    "age"":"18"

    }

    这时如果需要用上述对象;不能直接使用;

    let obj =new Object() || {};

    obj.name='张华'

    obj.age=18;

    若是直接应用

    改变里面的值;会产生同时改变

    关于Object.assign();对象拷贝问题(浅拷贝)

    深拷贝:

    使用扩展运算符...

    newway:  let obj = {name: 'mick', age: 10}

         let new obj = {...obj};

    way1:

    使用对象序列进行转化(原理就是将对象序列化成字符串,实现值的传递);

    let obj = {};

    let copy = JSON.parse(JSON.stringify(obj));

     /* way2 使用通信通道来实现对象的深拷贝*/
    let obj = {
    name: '小明',
    age: 20
    };
    function structuralClone(obj) {
    return new Promise(resolve => {
    const {port1, port2} = new MessageChannel();
    port2.onmessage = ev => resolve(ev.data);
    port1.postMessage(obj);
    });
    }
    let copy = structuralClone(obj);
    copy.then(res => {
    res.name = '小华';
    console.log(obj);
    console.log(res);
    })
    /* way3 使用浏览器内核 history 进行对象深拷贝*/
    function historyCopy(obj) {
    const oldState = history.state;
    history.replaceState(obj, document.title);
    const copy = history.state;
    history.replaceState(oldState, document.title);
    return copy;
    }
    let obj = {
    name: '小明',
    age: 20
    };
    const copy = historyCopy(obj);
    copy.name = '小孙';
    /*使用提醒Notification进行拷贝 */
    function NotificationCopy(obj) {
    return new Notification('', {data: obj, silent: true}).data;
    }
    const obj = {
    name: '小明',
    age: 20
    };
    const copy = NotificationCopy(obj);
    copy.name = '小孙';
    相信性能请查看(https://zhuanlan.zhihu.com/p/33489557)
    对于字符串类型,浅复制是对值的复制,对于对象来说,浅复制是对对象地址的复制,并没 有开辟新的栈,也就是复制的结果是两个对象指向同一个地址,修改其中一个对象的属性,则另一个对象的属性也会改变,而深复制则是开辟新的栈,两个对象对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性。

    二:

    在处理复杂的数据结构时;

    我们可以使用

    let obj={

        state:"1",

        parent:obj

        children:[

    {  

      state:2,

      parent:obj.children[0],

      children:[]

    }

    ]

    }

    注意点:一定值直接父级;为了好性能,一定要在选号最后结束;

    JSON.parse

    创建对象副本的最古老方法之一是:将该对象转换为其 JSON 字符串表示形式,然后将其解析回对象。这感觉有点压抑,但它确实有效:

    const obj = /* ... */;
    const copy = JSON.parse(JSON.stringify(obj));
    

    这里的缺点是你创建一个临时的,可能很大的字符串,只是为了把它重新放回解析器。另一个缺点是这种方法不能处理循环对象。而且循环对象经常发生。例如,当您构建树状数据结构,其中一个节点引用其父级,而父级又引用其子级。

    const x = {};
    const y = {x};
    x.y = y; // Cycle: x.y.x.y.x.y.x.y.x...
    const copy = JSON.parse(JSON.stringify(x)); // throws!
    

    另外,诸如 Maps, Sets, RegExps, Dates, ArrayBuffers 和其他内置类型在进行序列化时会丢失。

    Structured Clone 结构化克隆算法

    Structured cloning 是一种现有的算法,用于将值从一个地方转移到另一地方。例如,每当您调用postMessage将消息发送到另一个窗口或 WebWorker 时,都会使用它。关于结构化克隆的好处在于它处理循环对象并 支持大量的内置类型。问题是,在编写本文时,该算法并不能直接使用,只能作为其他 API 的一部分。我想我们应该了解一下包含哪些,不是吗。。。

    MessageChannel

    正如我所说的,只要你调用postMessage结构化克隆算法就可以使用。我们可以创建一个 MessageChannel 并发送消息。在接收端,消息包含我们原始数据对象的结构化克隆。

    function structuralClone(obj) {
      return new Promise(resolve => {
        const {port1, port2} = new MessageChannel();
        port2.onmessage = ev => resolve(ev.data);
        port1.postMessage(obj);
      });
    }
    
    const obj = /* ... */;
    const clone = await structuralClone(obj);
    

    这种方法的缺点是它是异步的。虽然这并无大碍,但是有时候你需要使用同步的方式来深度拷贝一个对象。

    History API

    如果你曾经使用history.pushState()写过 SPA,你就知道你可以提供一个状态对象来保存 URL。事实证明,这个状态对象使用结构化克隆 - 而且是同步的。我们必须小心使用,不要把程序逻辑使用的状态对象搞乱了,所以我们需要在完成克隆之后恢复原始状态。为了防止发生任何意外,请使用history.replaceState()而不是history.pushState()

    function structuralClone(obj) {
      const oldState = history.state;
      history.replaceState(obj, document.title);
      const copy = history.state;
      history.replaceState(oldState, document.title);
      return copy;
    }
    
    const obj = /* ... */;
    const clone = structuralClone(obj); 
    

    然而,仅仅为了复制一个对象,而使用浏览器的引擎,感觉有点过分。另外,Safari 浏览器对replaceState调用的限制数量为 30 秒内 100 次。

    Notification API

    在发了一条推文之后,Jeremy Banks 向我展示了第三种方法来利用结构化克隆:Notification API。

    function structuralClone(obj) {
      return new Notification('', {data: obj, silent: true}).data;
    }
    
    const obj = /* ... */;
    const clone = structuralClone(obj);
    

    短小,简洁。我喜欢它!

    但是,它需要浏览器内部的权限机制,所以我怀疑它是很慢的。由于某种原因,Safari 总是返回undefined

    Performance extravaganza

    我想测量哪种方法是最高性能的。在我的第一次(天真的)尝试中,我拿了一个小 JSON 对象,并通过不同的方式克隆对象 1 千次。幸运的是,Mathias Bynens 告诉我,当你添加属性到一个对象时,V8有一个缓存。所以我是在给缓存做基准测试。为了确保我永远不会碰到缓存,我编写了一个函数,使用随机密钥名称生成给定深度和宽度的对象,并重新运行测试

    图表!

    以下是 Chrome,Firefox 和 Edge 中不同技术的性能。越低越好。

    结论

    那么我们从中得到了什么呢?

    • 如果您没有循环对象,并且不需要保留内置类型,则可以使用跨浏览器的JSON.parse(JSON.stringify())获得最快的克隆性能,这让我感到非常惊讶。
    • 如果你想要一个适当的结构化克隆,MessageChannel是你唯一可靠的跨浏览器的选择。
  • 相关阅读:
    程序员的自我修养---------一个程序员应该懂点什么
    Duilib的圆环形 进度条 实现(网易云信版本)
    位定义,用于判断是否包含某属性
    Duilib的圆角矩形 抗锯齿优化 弥补RoundRect不足(网易云信borderround版本)
    exe、msi、dos、bat等静默运行,后台运行,不弹窗的解决办法
    删除桌面上有文件但提示项目不存在的方法
    MyBatis插入语句返回主键值
    django学习之Model(二)
    TCP三四次握手
    django学习之Model(一)
  • 原文地址:https://www.cnblogs.com/QxkWeb/p/7574590.html
Copyright © 2011-2022 走看看