如何在ES6 +中将两个javascript对象合并在一起?


141

我厌倦了总是不得不编写这样的代码:

function shallowExtend(obj1,obj2){
  var key;
  for ( key in obj2 ) {
    if ( obj2.hasOwnProperty(key) === false )  continue;
    obj1[key] = obj2[key]
  }
}

或者,如果我不想自己编写代码,请实现一个已经执行过的库。ES6 +肯定会在这方面获救,这将为我们提供类似a Object.prototype.extend(obj2...)Object.extend(obj1,obj2...)

那么ES6 +是否提供这种功能?如果尚不存在,那么是否计划了此类功能?如果没有计划,那为什么不呢?


3
那么你为什么不把它添加到您的图书馆吗?
RobG

12
@RobG这个问题是关于希望ES6将不必再需要这样的样板废话第一place.For删除我们什么是价值:github.com/balupton/bal-util/blob/...
balupton

我认为没有一种将名称/值对从一个对象复制到另一个对象的通用方法。您只处理自己的财产还是[[Prototype]]链上的财产?您是否进行“深层”或“浅层”副本?不可枚举和不可写的属性呢?我想我宁愿有一个小的库函数来满足我的需要,而且无论如何还是可以避免的。
RobG

Answers:


206

您将可以使用Object.assign在ES6中进行浅层合并/扩展/分配:

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

句法:

Object.assign(targetsources);

其中... sources表示源对象。

例:

var obj1 = {name: 'Daisy', age: 30};
var obj2 = {name: 'Casey'};

Object.assign(obj1, obj2);

console.log(obj1.name === 'Casey' && obj1.age === 30);
// true

64
一个小提示:Object.assign会改变目标。如果那不是您想要的,则可以使用一个空对象来调用它:let merged = Object.assign({}, source1, source2);
david

20
请注意,这是一个浅层扩展...嵌套对象未合并
monzonj 2016年

@monzonj,没有使用lodash或mout扩展嵌套对象的选项吗?
Joao Falcao

1
有一个很好的方法来合并深层嵌套的对象,而无需使用库Object.assign:仅在这里查看我的答案
Ruslan

扩展嵌套对象的一种旧方法是使用JSON.parse(JSON.stringify(src))
Andre Figueiredo,

162

您可以为此使用对象传播语法

const merged = {...obj1, ...obj2}

对于数组,散布运算符已经是ES6(ES2015)的一部分,但对于对象,它已添加到ES9(ES2018)的语言规范中。它的建议在很早以前就已在Babel等工具中默认启用。


3
现在没有正式名称为ES2015的:P自从什么时候解构不属于ES6?developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/…正在 运行babel-node:const ob1 = {foo: 123}; const ob2 = {bar: 234}; const merged = {...ob1, ...ob2}; console.log(merged) 输出:{ foo: 123, bar: 234 }
Thijs Koerselman

9
那不是破坏性的,它正在蔓延-不,对于对象来说,它不是ES6的一部分。您应该在Babel中禁用实验性ES7草稿。
Bergi

2
啊,原谅我 你是对的。此刻是babel阶段2的功能。github.com/sebmarkbage/ecmascript-rest-spread我从未意识到,因为我从babel开始就一直在使用它,并且默认情况下它是启用的。但是由于无论如何您都需要进行转换,并且对象扩散是一件非常简单的事情,因此我还是建议您这样做。我喜欢它。
Thijs Koerselman

它们是默认启用的,是吗?听起来像个错误。
Bergi 2015年

2
“默认情况下启用处于第2阶段或更高阶段的投标”。babeljs.io/docs/usage/experimental
Thijs Koerselman

13

我知道这是一个老问题,但是ES2015 / ES6中最简单的解决方案实际上很简单,使用Object.assign(),

希望这会有所帮助,这也会进行DEEP合并:

/**
 * Simple is object check.
 * @param item
 * @returns {boolean}
 */
export function isObject(item) {
  return (item && typeof item === 'object' && !Array.isArray(item) && item !== null);
}

/**
 * Deep merge two objects.
 * @param target
 * @param source
 */
export function mergeDeep(target, source) {
  if (isObject(target) && isObject(source)) {
    for (const key in source) {
      if (isObject(source[key])) {
        if (!target[key]) Object.assign(target, { [key]: {} });
        mergeDeep(target[key], source[key]);
      } else {
        Object.assign(target, { [key]: source[key] });
      }
    }
  }
  return target;
}

用法示例:

mergeDeep(this, { a: { b: { c: 123 } } });
// or
const merged = mergeDeep({a: 1}, { b : { c: { d: { e: 12345}}}});  
console.dir(merged); // { a: 1, b: { c: { d: [Object] } } }


7

ES6

Object.assign(o1,o2) ; 
Object.assign({},o1,o2) ; //safe inheritance
var copy=Object.assign({},o1); // clone o1
//------Transform array of objects to one object---
var subjects_assess=[{maths:92},{phy:75},{sport:99}];
Object.assign(...subjects_assess); // {maths:92,phy:75,sport:99}

ES7或Babel

{...o1,...o2} // inheritance
 var copy= {...o1};

1
@FilipBartuzi,不是您链接到的ES6。但是它基本上在lodash / underscore中等效于_.extend()。
Nostalg.io

5

也许ES5 Object.defineProperties方法能胜任?

例如

var a = {name:'fred'};
var b = {age: {value: 37, writeable: true}};

Object.defineProperties(a, b);

alert(a.age); // 37

MDN文档:https : //developer.mozilla.org/zh-CN/docs/JavaScript/Reference/Global_Objects/Object/defineProperties


不过要小心。在至少一个浏览器这会对性能产生影响。
Reuben Morais

1
我认为最有趣的部分是defineProperties定义自己的属性。它不会覆盖[[prototype]]链上的属性,而是将其阴影化。
RobG 2012年

2
一个很好的建议,尽管不是一个真正的扩展,因为它更多地用于定义属性的行为方式...做一个简单的Object.defineProperties(obj1,obj2)会导致意外的结果。
balupton

如果Object.getOwnPropertyDescriptor属性是复杂值,则还必须使用它来设置属性,否则您将通过引用进行复制。
dmp
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.