如何在另一个对象中复制对象属性?


184

给定对象:

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框架的情况实现解决方案?


3

1
问题是,您要浅拷贝还是深拷贝?如果深,有多深?
georg

5
FWIW,它们被称为“属性”,而不是“属性”。
TJ Crowder

这仍然是一件很丑陋的事情(实际上不建议这样做!只是一个单线的概念证明):secondObject = JSON.parse('{' + JSON.stringify(firstObject).match(/^.(.*).$/)[1] + ',' + JSON.stringify(secondObject).match(/^.(.*).$/)[1] + '}');
Ben Lee

@TJCrowder:我纠正了这个问题……谢谢。
伊戈尔·波波夫

Answers:


213
for(var k in firstObject) secondObject[k]=firstObject[k];

3
@BenLee,您在这里缺少的是Igor展示了他对此的确切用途,这hasOwnProperty是没有用的。尽管我发现您的指针很有用,但我认为将任何规则应用于任何情况的想法都是有害且不明智的。就像正在发生的所有这些模式驱动的开发实践一样,所以请不要个人化……
Michael Krelin-黑客2012年

1
@ MichaelKrelin-hacker,您在这里缺少的是StackOverflow不仅是为了OP的利益。它用作将来的访问者的参考,这些访问者可能会有稍微不同的用例,在这种情况下该指针可能会有用。
李·李

@BenLee,我不是IgorPopov ;-)而且不是OP,我已经说过,我发现指针很有用,您的回答也是如此,这是我不喜欢的“您应该真正使用”的部分。
Michael Krelin-黑客2012年

23
您省略了hasOwnProperty()测试,一切仍然可以正常进行。直到它们停止,因为您的对象随着时间的推移变得越来越复杂。否则,它会在代码的无关部分中神秘地中断,因为复制了太多内容。而且您没有任何调试上下文。JS很烂,因此,谨慎编码以防止此类问题的发生是谨慎的。
伊莱·班德斯基2013年

2
我认为这个答案需要根据以下链接进行更新developer.mozilla.org/en-US/docs/Web/JavaScript/Reference / ... const target = {a:1,b:2}; const source = {b:4,c:5}; const returnTarget = Object.assign(target,source); console.log(target); //预期的输出:对象{a:1,b:4,c:5} console.log(returnedTarget); //预期输出:对象{a:1,b:4,c:5}
Elbassel

170

从@Bardzuśny的答案中得到启发,ES6提供了一个本地解决方案:Object.assign()功能!

用法很简单:

Object.assign(secondObject, firstObject);

而已!

现在的支持显然很差;开箱即用仅支持Firefox(34+),而Chrome(45+)和Opera(32+)需要设置“ experimental flag”。

支持得到了改善,最新版本的Chrome,Firefox,Opera,Safari和Edge都支持它(IE显然不提供支持。)还可以使用Transpiler,例如Babel和Traceur。有关更多详细信息,请参见此处


4
+1,另一个很酷的ES6功能。当然,目前尚缺乏浏览器/甚至Node.JS的支持,但是正如您提到的,有可用的编译器。如果您不喜欢它们-垫片:github.com/paulmillr/es6-shim(或独立的- Object.assign()仅垫片:github.com/ljharb/object.assign)。
bardzusny

1
@Xoyce如果您检查链接的MDN页面,它会明确指出“如果源值是对对象的引用,则仅复制该引用值。” 因此,它确实会保留引用,并且不会复制对象。您针对意外行为的警告仍然很容易实现,并且可以归结为拥有适当的期望。
DIMM收割机,

@mostafiz我回滚了您的编辑,因为此页面上的问题和其他答案使用名称“ firstObject”和“ secondObject”,因此在这里使用相同的名称是为了清楚和一致。
DIMM收割机,

如果这与问题相符,那就可以了。
Mostafiz Rahman'8

1
@pdem是的-请参阅kingPuppy的答案
DIMM Reaper

100

根据ES6-传播语法

您可以简单地使用:

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

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

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


2
哇,这真的很棒:)感谢您的回答。显然,我不再需要它了(因为它已经有一段时间了),但是它可能会对其他人有所帮助。
伊戈尔·波波夫

1
+1使ES6的使用更加凉爽!上面引用的MDN文档未提及在对象上使用散布运算符,因此我摆弄了一个小提琴,以查看它的作用:es6fiddle.net/im3ifsg0
DIMM Reaper

1
@jaepage-好参考。具有简单属性名称的对象(按原始问题)可迭代的。
kingPuppy

1
可在Chrome中运行,这是ES6,您目前需要Babel或某些ES6编译器。将来希望所有浏览器都支持此语法。
kingPuppy

89

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

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在技​​术上正在使用。我认为他只是指自然语言“指代”。
李·李

1
@RobW:OP实际上确实说过“复制”。
TJ Crowder '02

49

在这里玩死灵法师,因为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 <9中不可用。.forEach()数组方法也是如此,我用它代替了常规方法。for循环。

幸运的是,有es5-shim这些古老的浏览器提供了可以许多ES5功能(包括这两个功能)。

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


突然,有2票投反对票。那些家伙会读这个评论的机会很小-他们的真正原因是什么?您有什么建议改变/改善我的答案吗?
bardzusny

1
这绝对应该上升到顶部,而对象扩展初始值设定项应该进一步下降(ES6)-使用箭头功能看起来更干净!
mjohnsonengr 16'Mar

12

死灵法使人们可以找到具有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;
};

请注意,这不会深度复制数组或函数对象(但是会深度复制所有其他种类的对象)。
马特·布朗

1
是的,如果您想深层复制数组,只需修改类型检查即可,以包括'[object Array]'
Nijikokun 2015年

12

一个可以使用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)吗?
TKoL

遗憾的是,根据该Mozilla开发人员网络页面,IE,Android WebView和Android Opera不支持该功能。
Yetti99 '18

6

改进kingPuppy想法和OP的想法(浅拷贝) -我只加3点至OP“榜样” :)

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


4

这应该工作,在这里进行测试。

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

注意:这不会复制firstObject
注释2的方法:要在较旧的浏览器中使用,您将需要json解析器。
注3:按引用分配是一个可行的选项,尤其是在firstObject包含方法的情况下。相应地调整了给定的jsfiddle示例


3

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

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 );

这还将复制本机属性。那么对象本身的属性呢?
KooiInc 2012年

1

如果你想抓住存在于第二对象的属性,你可以使用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;
}, {});

1

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

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

您能否在回答中提供一些背景信息,以及为什么它可以解决当前的问题
Tamir Klein

0

我宁愿使用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 / zh-CN / docs / Web / JavaScript / Reference / Global_Objects / Object / create

您也可以只分配值并省略描述符,并使它更短一些:

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

兼容性:ECMAScript 5,所以IE9 +


0
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很陌生,但是发现它可以正常工作。我猜有点太长了,但是可以用。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.