zoukankan      html  css  js  c++  java
  • javascript之如何复制一个对象

    Object是引用类型,对引用类型的赋值只是赋的内存地址。

    var foo = {
      a: "abc"
    }
    console.log(foo.a); // abc
     
    var bar = foo;
    console.log(bar.a); // abc
     
    foo.a = "yo foo";
    console.log(foo.a); // yo foo
    console.log(bar.a); // yo foo
     
    bar.a = "whatup bar?";
    console.log(foo.a); // whatup bar?
    console.log(bar.a); // whatup bar?
    

    foo和bar实际上是同一个对象的引用,bar并不能算作对foo的复制。
    复制对象有深拷贝和浅拷贝之分。

    浅拷贝

    如果对象比较简单、只具有值类型的属性,可以使用扩展运算符或 Object.assign()

    var obj = { foo: "foo", bar: "bar" }; 
    var copy = { ...obj }; // Object {foo: "foo", bar: "bar"}
    
    var obj = { foo: "foo", bar: "bar" };
    var copy = Object.assign({}, obj); // Object {foo: "foo", bar: "bar"}
    

    以上两种方法还可以用来合并对象。

    var obj1 = { foo: "foo" };
    var obj2 = { bar: "bar" };
     
    var copySpread = { ...obj1, ...obj2 }; // Object {foo: "foo", bar: "bar"}
    var copyAssign = Object.assign({}, obj1, obj2); // Object {foo: "foo", bar: "bar"}
    

    深拷贝

    针对深拷贝,需要使用其他办法,因为浅拷贝复制的是属性值。继承属性和不可枚举属性是不能拷贝的。假如源对象的属性值是一个对象的引用,那么它也只指向那个引用。

    //浅拷贝
    let obj1 = { a: 0 , b: { c: 0}}; 
    let obj2 = Object.assign({}, obj1); 
    obj2.b.c = 3; 
    console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 3}} 
    console.log(JSON.stringify(obj2)); // { a: 2, b: { c: 3}} 
    
    //深拷贝
    obj1 = { a: 0 , b: { c: 0}}; 
    let obj3 = JSON.parse(JSON.stringify(obj1)); 
    obj1.a = 4; 
    obj1.b.c = 4; 
    console.log(JSON.stringify(obj3)); // { a: 0, b: { c: 0}}
    

    然而这种方法也有其局限,此方法仅在原对象包含可序列化值类型且没有任何循环引用时才有效。
    对于复杂对象的深拷贝,MDN提供了一种方法

    const obj = {
      foo: 1,
      get bar() {
        return 2;
      }
    };
    
    let copy = Object.assign({}, obj); 
    console.log(copy); // { foo: 1, bar: 2 } copy.bar的值来自obj.bar的getter函数的返回值
    
    // 下面这个函数会拷贝所有自有属性的属性描述符
    function completeAssign(target, ...sources) {
      sources.forEach(source => {
        let descriptors = Object.keys(source).reduce((descriptors, key) => {
          descriptors[key] = Object.getOwnPropertyDescriptor(source, key);
          return descriptors;
        }, {});
    
        // Object.assign 默认也会拷贝可枚举的Symbols
        Object.getOwnPropertySymbols(source).forEach(sym => {
          let descriptor = Object.getOwnPropertyDescriptor(source, sym);
          if (descriptor.enumerable) {
            descriptors[sym] = descriptor;
          }
        });
        Object.defineProperties(target, descriptors);
      });
      return target;
    }
    
    copy = completeAssign({}, obj);
    console.log(copy);
    // { foo:1, get bar() { return 2 } }
    
  • 相关阅读:
    OI数学知识清单
    线段树入门教程
    扩展欧几里得定理基础讲解 代码及证明
    名字竞技场 V3.0
    可持久化线段树(主席树)新手向教程
    矩阵乘法浅析
    [Luogu] P1233 木棍加工
    高斯消元 模板
    位运算技巧
    [ZJOJ] 5794 2018.08.10【2018提高组】模拟A组&省选 旅行
  • 原文地址:https://www.cnblogs.com/Minstrel223/p/12786102.html
Copyright © 2011-2022 走看看