深拷贝

作者: bigtom | 来源:发表于2016-08-08 14:12 被阅读22次

    传值还是传引用

    传值还是传引用?很基础的问题,对于刚刚接触编程的同学来说,却是一个大坑。在js中,所有的对象都是通过引用来传递的。请默念一百遍。

    var foo = {
      bar: "bar"
    }
    var foo2 = foo
    foo2.bar = "baz"
    console.log(foo.bar)      // "baz"
    

    上面的代码中,我们改变foo2的属性的时候,其实就是改变了foo。因为在内存中,foo和foo2指向同一个instance。不信?试试就知道

    console.log(foo === foo2)      //"true"
    

    拷贝

    如果我们想要一个和foo一模一样的对象,但是并不指向内存中的同一个instance,怎么办呢?我们只需要重新创建一个空对象,然后把foo的属性全部复制过去就可以啦。

    function copy(obj){
      var res = {}
      for (var i in obj){
        res[i] = obj[i]
      }
      return res
    }
    
    var foo2 = copy(foo)
    foo2.bar = "baz"
    console.log(foo2.bar)
    console.log(foo.bar)
    

    下面我们的foo对象变得复杂了起来

    var foo = {
      bar: {
        baz: "baz"
      }
    }
    
    var foo2 = copy(foo)
    foo2.bar.baz = "newbaz"
    console.log(foo2.bar.baz)    //newbaz
    console.log(foo.bar.baz)      //newbaz
    

    问题出现了,foo对象中bar属性对应一个对象,我们在复制foo的过程中并没有真的复制bar对象,而是把它的引用取了过来,虽然现在foo和foo2不再是同一个对象,但是foo.bar和foo2.bar依然是同一个对象。

    console.log(foo === foo2)      //false
    console.log(foo.bar === foo2.bar)      //true
    

    深拷贝

    我们需要对对象进行深拷贝,也就是说,如果对象中的某个属性是一个对象,我们就要深入其中,将其复制,而不是取其引用。通过深度优先遍历对象树,将对象彻底的复制。

    function deepcopy(obj,res){
      var res = res || {};
      for (var i in obj){
        if (typeof obj[i] === 'object'){
          res[i] = (obj[i] instanceof Array) ? [] : {};
          deepcopy(obj[i],res[i]);
        }else{
          res[i] = obj[i]
        }
      }
      return res;
    }
    
    var foo = {
      bar: {
        baz: "baz"
      }
    }
    
    var foo2 = deepcopy(foo)
    foo2.bar.baz = "newbaz"
    console.log(foo2.bar.baz)      //"newbaz"
    console.log(foo.bar.baz)        //"baz"
    console.log(foo === foo2)    //false
    console.log(foo.bar === foo2.bar)      //false
    

    相关文章

      网友评论

          本文标题:深拷贝

          本文链接:https://www.haomeiwen.com/subject/oofrsttx.html