ES6 +で2つのJavaScriptオブジェクトをマージするにはどうすればよいですか?


141

私はいつもこのようなコードを書かなければならないことにうんざりしています。

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

または、自分でコードを記述したくない場合は、すでにそれを行うライブラリを実装します。確かにES6 +のようなものを提供してくれるだろう、この上の救助に来ています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

回答:


206

ES6では、Object.assignを使用して浅いマージ/拡張/割り当てを行うことができます。

https://developer.mozilla.org/en-US/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);
デヴィッド・

20
これは浅い拡張であることに注意してください...ネストされたオブジェクトはマージされません
monzonj 2016年

@ monzonj、lodashまたはmoutを使用せずにネストされたオブジェクトを拡張するオプションはありませんか?
ジョアンファルカン2016年

1
ジャストを使用してライブラリなしで深くネストされたオブジェクトをマージする良い方法がありますObject.assign私の答えをここで参照してください
Ruslan

ネストされたオブジェクトを拡張する古い方法が使用されていますJSON.parse(JSON.stringify(src))
Andre Figueiredo

162

これには、オブジェクトスプレッド構文を使用できます。

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

配列の場合、spread演算子はすでにES6(ES2015)の一部でしたが、オブジェクトの場合、ES9(ES2018)で言語仕様に追加されました。その提案は、それ以前からバベルのようなツールでデフォルトで有効にされていました。


3
正式にはそれは現在ES2015と呼ばれていません:P破壊はいつES6の一部ではないのですか?developer.mozilla.org/en-US/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の一部ではありません。バベルで実験的なES7ドラフトを無効にする必要があります。
Bergi

2
ああ、許して。あなたが正しいです。現時点ではバベルステージ2の機能です。github.com/sebmarkbage/ecmascript-rest-spread最初からbabelを使用していて、デフォルトで有効になっているため、そのことに気が付きませんでした。しかし、とにかくトランスパイルする必要があり、オブジェクトの広がりはかなり単純なものなので、とにかくそれをお勧めします。大好きです。
Thijs Koerselman、2015

デフォルトで有効になっていますか?それはバグのように聞こえます。
ベルギ

2
「ステージ2以上のプロポーザルはデフォルトで有効になっています」。babeljs.io/docs/usage/experimental
Thijs Koerselman、2015

14

私はこれが少し古い問題であることを知っていますが、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

の追加についてObject.mixinは、現在、要求されている動作を処理するために検討されています。https://mail.mozilla.org/pipermail/es-discuss/2012-December/027037.html

ES6のドラフトにはまだ載っていませんが、たくさんのサポートがあるようですので、まもなくドラフトに登場すると思います。


13
.mixinTC39によって削除されました。
Knu

5
警告 -この答えは正しくありません。正しい効果的なアプローチについては、ジャックの答えを参照してください。
Benjamin Gruenbaum 2015

Object.mixinはObject.assignに置き換えられました
gotofritz

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
リンクしたES6ではない@FilipBartuzi。しかし、基本的にはlodash / underscoreで_.extend()と同等のことをしています。
Nostalg.io 2017

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/en-US/docs/JavaScript/Reference/Global_Objects/Object/defineProperties


ただし、注意してください。上の少なくとも一つのブラウザこれは、パフォーマンスに影響があります。
ルーベンモレ

1
最も興味深い部分は、defineProperties独自のプロパティを定義することだと思います。[[prototype]]チェーンのプロパティを上書きするのではなく、それらをシャドウします。
RobG

2
プロパティの振る舞いを定義するためのものなので、実際には拡張ではありませんが、良い提案です。単純なObject.defineProperties(obj1、obj2)を実行すると、予期しない結果が発生します。
balupton 2012

Object.getOwnPropertyDescriptorプロパティが複雑な値である場合は、を使用してプロパティを設定する必要があります。そうしないと、参照によってコピーされます。
dmp
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.