zoukankan      html  css  js  c++  java
  • 小tips:使用JSON.parse(JSON.stringify(object))实现深拷贝的局限及扩展

    使用JSON.parse(JSON.stringify(object))实现深拷贝局限

    大部分情况我们都可以使用JSON.parse(JSON.stringify(object))来实现深拷贝,但该方法也有局限性,如下:

    • 会忽略 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"}

     借用 MessageChannel 实现深拷贝

    MessageChannel API允许我们创建一个新的消息通道,并通过它的两个MessagePort属性发送数据。

    var channel = new MessageChannel();

    这样就创建了一个管道。

    实例属性:

    channel.port1
    channel.port2

    获取实例的两个端口,注意的是,两个端口都是只读的。

    简单来说,MessageChannel创建了一个通信的管道,这个管道有两个端口,每个端口都可以通过postMessage发送数据,而一个端口只要绑定了onmessage回调方法,就可以接收从另一个端口传过来的数据。

    一个简单的例子:

    var channel = new MessageChannel();
    var port1 = channel.port1;
    var port2 = channel.port2;
    port1.onmessage = function(event) {
        console.log("port1收到来自port2的数据:" + event.data);
    }
    port2.onmessage = function(event) {
        console.log("port2收到来自port1的数据:" + event.data);
    }
    
    port1.postMessage("发送给port2");
    port2.postMessage("发送给port1");

    而通过 postMessage() 方法传输的 message 参数是深拷贝的。

    function deepClone(val) {
        return new Promise((resolve,reject) => {
            const {port1,port2} = new MessageChannel();
            port2.onmessage = e => resolve(e.data);
            port1.postMessage(val);
        })
    }
    
    let obj = {
      age: undefined,
      name: 'yck',
      c: {
          d: true
      }
    }
    obj.c.e = obj.c; // 循环引用
    
    // 注意该方法是异步
    async function test() {
        const clone = await deepClone(obj);
        console.log(clone) // {age: undefined, name: "yck", c: {…}}
    }
    test()

    但这个深拷贝只能解决 undefined 和循环引用对象的问题,对于 Symbol 和 function 依然束手无策。

    详细可参考:《MessageChannel 消息通道》

    简易版的深拷贝

    var extendCopy = (function f(p,c){
        var c = c || {};
        for (var i in p) {
            if(typeof p[i] === 'object'){
                c[i] = (p[i] instanceof Array) ? [] : {};
                f(p[i],c[i]);
            }else{
                 c[i] = p[i];
            } 
        }
        return c;
    });

    详细可参考:《小tips:JS之浅拷贝与深拷贝》

    lodash 的深拷贝函数

    语法:

    _.cloneDeep(value)

    示例:

    var objects = [{ 'a': 1 }, { 'b': 2 }];
     
    var deep = _.cloneDeep(objects);
    console.log(deep[0] === objects[0]);
    // => false

    地址:https://lodash.com/docs/4.17.15#cloneDeep

  • 相关阅读:
    进程、线程、协程
    C++内存模型
    动态库dll与静态库lib
    virtual 虚函数表
    C++面试随笔
    alloc()、malloc()、calloc()、realloc()区别及用法
    C/C++ 面试题记录
    VC底层钩子程序在Win7/Vista下无效
    JMeter安装之后修成中文版
    明天开始 新的旅程
  • 原文地址:https://www.cnblogs.com/moqiutao/p/14171405.html
Copyright © 2011-2022 走看看