【问题标题】:How to duplicate object properties in another object? [duplicate]如何在另一个对象中复制对象属性? [复制]
【发布时间】:2012-03-10 21:17:39
【问题描述】:

给定对象:

var firstObject = {
    key1 : 'value1',
    key2 : 'value2'
};

如何在另一个对象中复制属性 (secondObject),如下所示:

var secondObject = {
    key1 : 'value1',
    key2 : 'value2',
    key3 : 'value3',
    key4 : 'value4'
};

使用对firstObject的引用?像这样的:

var secondObject = {
    firstObject,
    key3 : 'value3',
    key4 : 'value4'
};

(这行不通……我把它放在大行中只是为了显示我想如何构造代码)。

不使用任何 JavaScript 框架是否可行?

【问题讨论】:

  • 问题是,你想要浅拷贝还是深拷贝?如果深,多深?
  • FWIW,它们被称为“属性”,而不是“属性”。
  • 这里有一些非常丑陋但仍然有效的东西(实际上并不推荐!只是一个单行概念验证):secondObject = JSON.parse('{' + JSON.stringify(firstObject).match(/^.(.*).$/)[1] + ',' + JSON.stringify(secondObject).match(/^.(.*).$/)[1] + '}');
  • @T.J.Crowder:我更正了这个问题......谢谢。

标签: javascript


【解决方案1】:
for(var k in firstObject) secondObject[k]=firstObject[k];

【讨论】:

  • @BenLee,你在这里缺少的是 Igor 已经展示了他对它的确切用途,其中hasOwnProperty 是无用的。虽然我发现您的指针很有用,但我认为将 any 规则应用于 any 情况的想法有害且不明智。就像所有这些正在发生的模式驱动的开发实践一样,所以不要把它当作个人......
  • @MichaelKrelin-hacker,您在这里缺少的是 StackOverflow 不仅仅是为了 OP 的利益。它被用作未来访问者的参考,这些访问者的用例可能略有不同,该指针可能很有用。
  • @BenLee,我不是 IgorPopov ;-) 而且不是 OP,我已经说过我发现指针很有用,你的答案也是,它是“你应该真正使用”的部分我不喜欢的。
  • 你省略了hasOwnProperty() 测试,事情还挺正常的。直到它们停止,因为您的对象随着时间的推移变得更加复杂。除非它在代码的不相关部分神秘地中断,因为复制了太多。而且您没有任何调试上下文。 JS 就是这么烂,所以谨慎的编码以防止此类问题的发生是谨慎的。
  • 我认为这个答案需要根据以下链接更新developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… const target = { a: 1, b: 2 };常量源 = { b: 4, c: 5 };常量返回目标 = Object.assign(目标,源);控制台.log(目标); // 预期输出:Object { a: 1, b: 4, c: 5 } console.log(returnedTarget); // 预期输出:Object { a: 1, b: 4, c: 5 }
【解决方案2】:

从@Bardzuśny 的回答中得到启发,ES6 提供了一个原生解决方案:Object.assign() 函数!

用法很简单:

Object.assign(secondObject, firstObject);

就是这样!

现在的支持显然很差;只有 Firefox (34+) 支持开箱即用,而 Chrome (45+) 和 Opera (32+) 需要设置“实验标志”。

支持正在改进,最新版本的 Chrome、Firefox、Opera、Safari 和 Edge 都支持它(IE 显然不支持。)也可以使用转译器,如 Babel 和 Traceur。 See here了解更多详情。

【讨论】:

  • +1,另一个很酷的 ES6 特性。当然,浏览器/甚至 Node.JS 目前还缺乏支​​持,但正如您所提到的,有可用的转译器。如果您不喜欢它们 - 垫片:github.com/paulmillr/es6-shim(或独立的,Object.assign()-only 垫片:github.com/ljharb/object.assign)。
  • @Xoyce 如果您检查链接的 MDN 页面,它清楚地指出“如果源值是对对象的引用,它只会复制该引用值。”所以它确实保留了引用,并且不复制对象。您对意外行为的警告仍然很恰当,归结为要有适当的期望。
  • 现在还有 3 个点的“扩展运算符”:thirdObject={...firstObject ,...secondObject}
  • @pdem 是的 - 请参阅 kingPuppy's answer。
  • 请注意,它只适用于 ES6....例如在 IE 中它不起作用。
【解决方案3】:

每ES6 - Spread syntax:

你可以简单地使用:

const thirdObject = {
   ...firstObject,
   ...secondObject   
}

这避免了通过引用传递这些对象的问题。

此外,它还处理具有深度嵌套的对象。

【讨论】:

  • 哇,这真是太棒了:) 感谢您的回答。显然,我不再需要它(因为它是不久前的),但它可能会帮助其他人。
  • +1 更酷地使用 ES6!上面引用的 MDN 文档没有提到在对象上使用扩展运算符,所以我做了一个小提琴来看看它的实际效果:es6fiddle.net/im3ifsg0
  • @jaepage - 很好的评论供参考。具有简单属性名称的对象(根据原始问题)是可迭代的。
  • 在 Chrome 中工作,这是 ES6,您目前需要 Babel 或一些 ES6 转译器。未来所有浏览器都应该支持这种语法。
【解决方案4】:

遍历第一个对象的属性并将它们分配给第二个对象,如下所示:

var firstObject = {
    key1 : 'value1',
    key2 : 'value2'
};

var secondObject = {
    key3 : 'value3',
    key4 : 'value4'
};

for (var prop in firstObject) {
    if (firstObject.hasOwnProperty(prop)) {
        secondObject[prop] = firstObject[prop];
    }
}

for-in 循环是不够的;你需要hasOwnProperty。有关原因的详细说明,请参阅http://bonsaiden.github.com/JavaScript-Garden/#object.forinloop。

【讨论】:

  • @RobW,我不认为 OP 在技术意义上使用 reference。我认为他只是指自然语言中的“指代”。
  • @RobW:OP 实际上确实说“复制”。
  • 您实际上需要if(Object.prototype.hasOwnProperty.call(firstObject, prop)){} 才能更安全。 eslint.org/docs/rules/no-prototype-builtins
【解决方案5】:

在这里扮演死灵法师,因为 ES5 为我们带来了Object.keys(),有可能将我们从所有这些.hasOwnProperty() 检查中拯救出来。

Object.keys(firstObject).forEach(function(key) {
  secondObject[key] = firstObject[key];
});

或者,将其包装成一个函数(lodash _.assign() 的有限“副本”):

function assign(object, source) {
  Object.keys(source).forEach(function(key) {
    object[key] = source[key];
  });
}

assign(secondObject, firstObject); // assign firstObject properties to secondObject

Object.keys() 是相对较新的方法,最值得注意的是:在 IE .forEach() 数组方法实际上也是如此,我用它代替了常规的 for 循环。

幸运的是,es5-shim 可用于这些古老的浏览器,它将填充许多 ES5 特性(包括这两个特性)。

(我完全支持 polyfill,而不是阻止使用很酷的新语言功能。)

【讨论】:

  • 突然间,2 票投反对票。假设这些人会阅读此评论的可能性很小-他们的实际原因是什么?您有什么建议可以更改/改进我的回答吗?
  • 这绝对值得升到顶部,以及进一步向下的对象传播初始化程序(ES6)——这看起来更清晰的箭头函数!
【解决方案6】:

可以使用Object.assign 来组合对象。它将从右到左组合并覆盖公共属性,即左侧的相同属性将被右侧覆盖。

重要首先提供一个空对象以避免改变源对象。源对象应该保持干净,因为 Object.assign() 本身会返回一个新对象。

希望这会有所帮助!

var firstObject = {
    key1 : 'value1',
    key2 : 'value2'
};

var secondObject = {
    key3 : 'value3',
    key4 : 'value4'
};

var finalObject = Object.assign({}, firstObject, secondObject)

console.log(finalObject)

【讨论】:

  • 但是如果你想要它来改变第一个对象呢?您有对象 A 和对象 B,并且您希望它改变对象 A 以使所有属性都等于对象 B 上的属性?你会做 Object.assign(A, B) 吗?
  • 遗憾的是,根据 Mozilla 开发者网络页面,IE、Android WebView、Android Opera 不支持。
【解决方案7】:

Necro'ing 以便人们可以使用 hasOwnProperty 和实际对象检查找到深层复制方法:

var extend = function (original, context, key) {
  for (key in context)
    if (context.hasOwnProperty(key))
      if (Object.prototype.toString.call(context[key]) === '[object Object]')
        original[key] = extend(original[key] || {}, context[key]);
      else
        original[key] = context[key];
  return original;
};

【讨论】:

  • 请注意,这不会深度复制数组或函数对象(但它会深度复制所有其他类型的对象)。
  • 是的,如果你想深拷贝数组,你只需修改类型检查以包含'[object Array]'
【解决方案8】:

改进kingPuppyidea和OPidea(浅拷贝)——我只在OP“示例”中添加3个点:)

var secondObject = {
    ...firstObject,
    key3 : 'value3',
    key4 : 'value4'
};

var firstObject = {
    key1 : 'value1',
    key2 : 'value2'
};

var secondObject = {
    ...firstObject,
    key3 : 'value3',
    key4 : 'value4'
};

console.log(secondObject);

【讨论】:

    【解决方案9】:

    这应该可以工作,经过测试here。

    var secondObject = {
        firstObject: JSON.parse(JSON.stringify(firstObject)),
        key3 : 'value3',
        key4 : 'value4'
    };
    

    注意:这不会复制 firstObject 的方法
    注意 2:要在旧版浏览器中使用,您需要 json parser
    注意 3:通过引用分配是一个可行的选择,尤其是当 firstObject 包含方法时。相应地调整了给定的 jsfiddle 示例

    【讨论】:

      【解决方案10】:

      不幸的是,您不能将对变量的引用放在这样的对象中。但是,您可以创建一个将对象的值复制到另一个对象的函数。

      function extend( obj1, obj2 ) {
          for ( var i in obj2 ) {
              obj1[i] = obj2[i];
          }
          return obj1;
      }
      
      var firstObject = {
          key1: "value1",
          key2: "value2"
      };
      
      var secondObject = extend({
          key3: "value3",
          key4: "value4"
      }, firstObject );
      

      【讨论】:

      • 这也将复制本机属性。那么作为对象本身的属性呢?
      【解决方案11】:

      使用属性扩展符号。它是在 ES2018 中添加的(数组/可迭代的传播更早,ES2015), {...firstObject} 将所有可枚举属性作为离散属性展开。

      let secondObject = {
            ...firstObject,
            key3 : 'value3',
            key4 : 'value4'
          }
      

      【讨论】:

      • 能否请您提供一些关于您的答案的背景信息以及为什么它可以解决手头的问题
      • 如果我没记错的话,我认为 OP 不希望将 firstObject 作为离散属性传播到 secondObject 中。他想将 firstObject 深度复制到 second 中,并将 firstObject 键保留在 secondObject 中。
      【解决方案12】:

      如果你想只抓取第二个对象中存在的属性,你可以使用Object.keys来抓取第一个对象的属性,有两种方法:

      A.) map 使用副作用将第一个对象的属性分配给第二个对象:

      var a = {a:100, b:9000, c:300};
      var b = {b:-1};
      
      Object.keys(a).map(function(key, index) {
          if (typeof b[key] !== 'undefined') {
              console.log(key);
              b[key] = a[key];    
          }
      });
      

      B.) 或reduce 创建一个新对象并将其分配给第二个对象。请注意,此方法替换第二个对象在与第一个对象不匹配的属性之前可能具有的其他属性:

      var a = {a:100, b:9000, c:300};
      var b = {b:-1, d:-1}; // d will be gone
      
      b = Object.keys(a).reduce(function(result, current) {
          if (typeof b[current] !== 'undefined') {
              result[current] = a[current];   
          }
          return result;
      }, {});
      

      【讨论】:

        【解决方案13】:

        为了记录,现在也可以这样做

        var firstObject = {
            key1 : 'value1',
            key2 : 'value2'
        };
        
        var secondObject = {
            ...firstObject,
            key3 : 'value3',
            key4 : 'value4'
        };
        

        【讨论】:

          【解决方案14】:

          我宁愿使用 firstObject 作为 secondObject 的原型,并添加属性描述符:

          var secondObject = Object.create(firstObject, {
                key3: {value: "value3", writable: true, configurable: true, enumerable: true},
                key4: {value: "value4", writable: true, configurable: true, enumerable: true}
                });
          

          它当然不是单行的,但它可以让您更好地控制。如果你对属性描述符感兴趣,我建议阅读这篇文章:http://patrickdelancy.com/2012/09/property-descriptors-in-javascript/#comment-2062 和MDN页面https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create

          您也可以只分配值并省略描述符并使其更短:

          var secondObject = Object.create(firstObject, {
                key3: {value: "value3"}
                key4: {value: "value4"}
            });
          

          兼容性:ECMAScript 5,所以 IE9+

          【讨论】:

            【解决方案15】:
            var firstObject = {
                 key1: "value1",
                 key2: "value2"
            };
            
            var secondObject = {
                 key3: "value3",
                 key4: "value4"
                 copy: function(firstObject){
                       this.key1 = firstObject.key1;
                       this.key2 = firstObject.key2;
                 }
             };
            

            使用以下方法将复制属性

            secondObject.copy(firstObject)
            

            我对 javascript 很陌生,但发现这很有效。我猜有点太长了,但它有效。

            【讨论】:

              【解决方案16】:

              Object.assign 或解构可能会严重影响您,因为只有顶级属性会被复制为值。

              所有嵌套属性都将被复制为引用,并保留对原始对象属性的引用。如果你的物体是平的,那没关系。但如果不是,这些灵魂就很少适用了。

              对于最简单和有效的单线我会推荐deepmerge 包,它没有这个缺点。

              const newObject = deepmerge({}, oldObjectWithNestedProperties);
              

              这将为您提供您的oldObjectWithNestedProperties 的完全独立和独立的newObject 副本。

              【讨论】:

                猜你喜欢
                • 2017-05-08
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2014-12-15
                • 2014-12-08
                相关资源
                最近更新 更多