複数のJavaScriptオブジェクトのプロパティを連結する方法


105

複数のJavaScriptオブジェクト(連想配列)を「追加」する最良の方法を探しています。

たとえば、次の場合:

a = { "one" : 1, "two" : 2 };
b = { "three" : 3 };
c = { "four" : 4, "five" : 5 };

計算する最良の方法は何ですか:

{ "one" : 1, "two" : 2, "three" : 3, "four" : 4, "five" : 5 }

3
セマンティックノート:[]構文にもかかわらず、それらは配列ではありません。順序は保証されていません。
アルバロ・ゴンサレス

1
繰り返し順序はECMA標準ごとに保証されていません。しかし、ほとんどのブラウザでの実装方法です。(John Resigから)この動作は、ECMAScript仕様では明示的に定義されていません。ECMA-262のセクション12.6.4:プロパティを列挙するメカニズム...は実装に依存します。ただし、仕様は実装とはかなり異なります。ECMAScriptの最新の実装はすべて、オブジェクトプロパティが定義された順序で繰り返されます。このため、Chromeチームはこれをバグと見なし、修正する予定です。
ファンメンデス

回答:


159

Object.assign()これをJavascriptでネイティブに実現するために導入されたECMAscript 6 。

Object.assign()メソッドは、ターゲット・オブジェクトに1つ以上のソースオブジェクトからすべての列挙独自のプロパティの値をコピーするために使用されます。ターゲットオブジェクトを返します。

Object.assign()に関するMDNドキュメント

var o1 = { a: 1 };
var o2 = { b: 2 };
var o3 = { c: 3 };

var obj = Object.assign({}, o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }

Object.assign最近の多くのブラウザでサポートされていますが、まだすべてではありません。BabelTraceurなどのトランスパイラーを使用して、下位互換性のあるES5 JavaScriptを生成します。


4
これは私が言える最高の1つです。現在E6が主に使用されているため、Object.assignが最良の答えです。
Vimalraj Selvam 2016

6
あなたは彼らが配列であるbevause次のようにあなたがそれらをマージすることができ、マージする必要がありますどのように多くのオブジェクトがわからない場合:Object.assign.apply({}, [{a: 1}, {b: 2}, ....])
Jeanluca Scaljeri

1
使用する代わりにObject.assign.applyオブジェクトの配列をマージするために、代わりに拡散演算子を使用することである:Object.assign( ...objects )
SPEN

この質問への回答としてすでに含まれている@Spen。ここでそれを複製することの利点は見ていません。
filoxo 2018

4時間後、この回答はAngular 7での私の問題を解決しました。回答の簡潔さと正確さをありがとう。
Gel

35

次の$.extendようなjqueryを使用できます。

let a = { "one" : 1, "two" : 2 },
    b = { "three" : 3 },
    c = { "four" : 4, "five" : 5 };

let d = $.extend({}, a, b, c)

console.log(d)
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>


+1 jQueryのメソッドを使用しない場合でも、それらのコードを使用して、独自の(おそらく、より具体的な)実装を構築できます。
tvanfosson

25
@Randal:jQueryを使用しない理由はたくさんあります。
Tim Down

3
編集:d = $.extend({},a,b,c);
ボブスタイン

34

これはそれを行うはずです:

function collect() {
  var ret = {};
  var len = arguments.length;
  for (var i = 0; i < len; i++) {
    for (p in arguments[i]) {
      if (arguments[i].hasOwnProperty(p)) {
        ret[p] = arguments[i][p];
      }
    }
  }
  return ret;
}

let a = { "one" : 1, "two" : 2 };
let b = { "three" : 3 };
let c = { "four" : 4, "five" : 5 };

let d = collect(a, b, c);
console.log(d);

出力:

{
  "one": 1,
  "two": 2,
  "three": 3,
  "four": 4,
  "five": 5
}

length各呼び出しで配列のサイズを検索しませんか?私は執筆に慣れているのでfor (var i = 0, len = array.length; i < len; ++i)、なぜ始めたのか頭の上から思い出すことができません。
tvanfosson 2010年

1
それは正解です。長さを1回キャッシュする方がパフォーマンスが向上します。ただし、引数の「配列」のサイズは非常に大きくなる可能性は低いため、この場合は問題になりません。
jhurshman 2010年

1
いいえ、IE6を少し除いて。lengthプロパティへのアクセスには、len変数へのアクセスと同じコストがかかります。
アルシエンデ2010年

1
@フアン私はあなたが間違っていると思います、そして私は私の決心のためにいくつかのテストをしました。長さをキャッシュすることは、長年廃止されてきた最適化の簡単な神話であり、コードを(少し)読みにくくします。実際には、長さをキャッシュするとブラウザー(Safari)が遅くなることがあります。
Alsciende 2010年

2
「for(p in ...」の代わりに「for(var p in ...」と書く方がいいのではないですか?
Hugo

24

ECMAScript 6には構文広がっています。そして今、これを行うことができます:

const obj1 = { 1: 11, 2: 22 };
const obj2 = { 3: 33, 4: 44 };
const obj3 = { ...obj1, ...obj2 };

console.log(obj3); // {1: 11, 2: 22, 3: 33, 4: 44}


12

アンダースコアには、これを行うためのいくつかの方法があります。

1. _.extend(destination、* sources)

プロパティのすべてのコピー元がにオーバーオブジェクト先のオブジェクト、および戻り先のオブジェクトを。

_.extend(a, _.extend(b, c));
=> {"one" : 1, "two" : 2, "three" : 3, "four" : 4, "five" : 5 }

または

_.extend(a, b);
=> {"one" : 1, "two" : 2, "three" : 3}
_.extend(a, c);
=> {"one" : 1, "two" : 2, "three" : 3, "four" : 4, "five" : 5 }

2. _.defaults(オブジェクト、*デフォルト)

記入未定義のプロパティオブジェクトの値とデフォルトのオブジェクト、および戻りオブジェクト

_.defaults(a, _.defaults(b, c));
=> {"one" : 1, "two" : 2, "three" : 3, "four" : 4, "five" : 5 }

または

_.defaults(a, b);
=> {"one" : 1, "two" : 2, "three" : 3}
_.defaults(a, c);
=> {"one" : 1, "two" : 2, "three" : 3, "four" : 4, "five" : 5 }

4

関数を3つの引数に制限する必要があるのはなぜですか?また、を確認してくださいhasOwnProperty

function Collect() {
    var o={};
    for(var i=0;i<arguments.length;i++) {
      var arg=arguments[i];
      if(typeof arg != "object") continue;
      for(var p in arg) {
        if(arg.hasOwnProperty(p)) o[p] = arg[p];
      }
    }
    return o;
}

4

Object.assign()より短い構文を使用して、シャロークローニング(プロトタイプを除く)またはオブジェクトのマージが可能になりました。

スプレッド構文のためのオブジェクトリテラルは中に導入された 2018年のECMAScript):

const a = { "one": 1, "two": 2 };
const b = { "three": 3 };
const c = { "four": 4, "five": 5 };

const result = {...a, ...b, ...c};
// Object { "one": 1, "two": 2 , "three": 3, "four": 4, "five": 5 }

スプレッド(...)演算子は、最新の多くのブラウザーでサポートされていますが、すべてではありません。

したがって、Babelのようなトランスパイラーを使用して、ECMAScript 2015+コードを、現在および以前のブラウザーまたは環境で下位互換性のあるJavaScriptバージョンに変換することをお勧めします。

これは、Babelが生成する同等のコードです。

"use strict";

var _extends = Object.assign || function(target) {
  for (var i = 1; i < arguments.length; i++) {
    var source = arguments[i];
    for (var key in source) {
      if (Object.prototype.hasOwnProperty.call(source, key)) {
        target[key] = source[key];
      }
    }
  }
  return target;
};

var a = { "one": 1, "two": 2 };
var b = { "three": 3 };
var c = { "four": 4, "five": 5 };

var result = _extends({}, a, b, c);
// Object { "one": 1, "two": 2 , "three": 3, "four": 4, "five": 5 }

これは、受け入れられた回答よりもはるかに堅牢な回答です。ありがとう!
カレブアンダーソン

3
function Collect(a, b, c) {
    for (property in b)
        a[property] = b[property];

    for (property in c)
        a[property] = c[property];

    return a;
}

注意:以前のオブジェクトの既存のプロパティは上書きされます。


2
これには、a === d最後に副作用があります。それは大丈夫かもしれませんし、そうでないかもしれません。
tvanfosson 2010年

2

ES7スプレッドオペレーターをオブジェクトに使用するのは簡単です。

({ name: "Alex", ...(true  ? { age: 19 } : { })}) // {name: "Alex", age: 19}
({ name: "Alex", ...(false ? { age: 19 } : { })}) // {name: "Alex",        }

1
いいね。この質問は10年以上前のもので、このような単純な操作が簡単にできることをうれしく思います。他の人の答えを見ると、以前はそれほど簡単ではありませんでした。
Vlad

それが私が自分の答えを残した理由です:)
Purkhalo Alex

2

動的な数のオブジェクトをマージするにはObject.assignspread syntaxを使用できます

const mergeObjs = (...objs) => Object.assign({}, ...objs);

上記の関数は任意の数のオブジェクトを受け入れ、すべてのプロパティを新しいオブジェクトにマージし、新しいオブジェクトのプロパティを以前のオブジェクトのプロパティに上書きします。

デモ:

オブジェクトの配列をマージするには、同様の方法を適用できます。

const mergeArrayOfObjs = arr => Object.assign({}, ...arr);

デモ:


1

おそらく、最も速く、効率的で、より一般的な方法はこれです(任意の数のオブジェクトをマージし、最初のオブジェクトにコピーすることもできます-> assign):

function object_merge(){
    for (var i=1; i<arguments.length; i++)
       for (var a in arguments[i])
         arguments[0][a] = arguments[i][a];
   return arguments[0];
}

また、参照渡しされた最初のオブジェクトを変更することもできます。これが不要で、すべてのプロパティを含む完全に新しいオブジェクトが必要な場合は、最初の引数として{}を渡すことができます。

var object1={a:1,b:2};
var object2={c:3,d:4};
var object3={d:5,e:6};
var combined_object=object_merge(object1,object2,object3); 

bound_objectとobject1の両方に、object1、object2、object3のプロパティが含まれています。

var object1={a:1,b:2};
var object2={c:3,d:4};
var object3={d:5,e:6};
var combined_object=object_merge({},object1,object2,object3); 

この場合、combined_objectには、object1、object2、object3のプロパティが含まれていますが、object1は変更されていません。

ここをチェックしてください:https//jsfiddle.net/ppwovxey/1/

注:JavaScriptオブジェクトは参照渡しされます。


1

ES6 ++

問題は、さまざまな異なるオブジェクトを1つに追加することです。

let obj = {};
const obj1 = { foo: 'bar' };
const obj2 = { bar: 'foo' };
Object.assign(obj, obj1, obj2);
//output => {foo: 'bar', bar: 'foo'};

オブジェクトである複数のキーを持つ1つのオブジェクトがあるとします。

let obj = {
  foo: { bar: 'foo' },
  bar: { foo: 'bar' }
}

これは私が見つけた解決策でした(まだforeachする必要があります:/)

let objAll = {};

Object.values(obj).forEach(o => {
  objAll = {...objAll, ...o};
});

これにより、すべてのオブジェクトキーを動的に1つに追加できます。

// Output => { bar: 'foo', foo: 'bar' }


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.