[深拷贝]js七种方法

3,280 阅读3分钟
  1. 使用递归方式进行深拷贝
  2. 通过JSON对象实现深拷贝
  3. 使用jq(extend)方法实现深拷贝
  4. object.assign()实现深拷贝
  5. lodash函数库实现深拷贝
  6. MessageChannel实现深拷贝
  7. Web Worker实现深拷贝


惊呆了!原来深拷贝有这么多种。。。

接下来我们逐一介绍下:

1.使用递归方式进行深拷贝:

function Clone(obj) {
   //先判断是数组还是对象(执行对应的拷贝)
   var objCopy = Array.isArray(obj) ? [] : {};
  //拷贝的对象不能为空
   if (obj && typeof obj === "object") {
         for (key in obj) {//遍历
           if (obj.hasOwnProperty(key)) {
                //拷贝的对象不能为空
              if (obj[key] && typeof obj[key] === "object") {
                 objCopy[key] = Clone(obj[key]);
               } else {
                  objCopy[key] = obj[key];
               }
            }
         }
     }
   return objCopy;
}

2.JSON对象实现深拷贝

function Clone(obj) {
  var Copyobj = JSON.stringify(obj),
    //json字符串转json对象
    objClone = JSON.parse(Copyobj);
  return objClone;
}

*注意事项*

(2-1)如果obj里有RegExp、Error对象,则序列化的结果将只得到空对象

(2-2)如果obj里面有时间对象,则JSON.stringify后再JSON.parse的结果,时间将只是字符串的形式。而不是时间对象

(2-3)如果obj里有函数,undefined,则序列化的结果会把函数或 undefined丢失

(2-4)如果obj里有NaN、Infinity和-Infinity,则序列化的结果会变成null

(2-5)无法处理function,无法处理循环引用对象


3.使用jq(extend)方法实现深拷贝

var obj= {
  a:10,
  b:function (){
    console.log(this.a)
  }
};
var newObj = $.extend(true,{},obj);

*注意*

$.extend中的true为深拷贝 false为浅拷贝

其实是把第二个对象上面的属性和对象覆盖到第一个对象上面


4.object.assign()实现深拷贝

  var obj1 = { a: 0 , b: { c: 0}};
  var obj2 = Object.assign({}, obj1);

*注意*

当对象中只有一级属性,没有二级属性的时候,此方法为深拷贝,但是对象中有对象的时候,此方法,在二级属性以后就是浅拷贝。


5.lodash函数库实现深拷贝

lodash很热门的函数库,提供了 lodash.cloneDeep()实现深拷贝
var abj={
 a:1,
 b:2
}
var copyobj = lodash.cloneDeep(abj)

*注意*

层级太多的复杂对象拷贝可能会出现报错(其内部使用递归拷贝实现)


*/接下来看看几个偏门的深拷贝/*


6.MessageChannel实现深拷贝

    let obj = {      a: 1,      b: {        c: 2,        d: 3,      },      f: undefined    }    obj.c = obj.b;    obj.e = obj.a    obj.b.c = obj.c    obj.b.d = obj.b    obj.b.e = obj.b.c
    function deepCopy(obj) {      return new Promise((resolve) => {        const {port1, port2} = new MessageChannel();        port2.onmessage = ev => resolve(ev.data);        port1.postMessage(obj);      });    }
    deepCopy(obj).then((copy) => {           // 请记住`MessageChannel`是异步的这个前提!        let copyObj = copy;        console.log(copyObj, obj)        console.log(copyObj == obj)    });


*注意*

虽然能实现深拷贝,但拷贝有函数的对象时,还是会报错

MessageChannel接口允许创建一个新的消息通道,并通过它的两个MessagePort属性发送数据。MessageChannel接口实例化以后,会有两个属性port1port2.)

主要是用来做通道通信的


7.Web Worker实现深拷贝

    var w1 = new Worker("worker1.js");
    var w2 = new Worker("worker2.js");
    var ch = new MessageChannel();
    w1.postMessage("port1", [ch.port1]);
    w2.postMessage("port2", [ch.port2]);
    w2.onmessage = function(e) {
        console.log(e.data);
  }

// worker1.js
  onmessage = function(e) {
    const  port = e.ports[0];
    port.postMessage("this is from worker1")        
  }

// worker2.js
    onmessage = function(e) {
        const port = e.ports[0];
        port.onmessage = function(e) {
            postMessage(e.data)
           
        }
    }

我们通过给w2绑定onmessage回调函数来验证传递是否成功输出this is from worker1

Web Workers 使得一个Web应用程序可以在与主执行线程分离的后台线程中运行一个脚本操作。这样做的好处是可以在一个单独的线程中执行费时的处理任务,从而允许主(通常是UI)线程运行而不被阻塞/放慢。