オブジェクトのマージ(連想配列)


147

JavaScriptで2つの連想配列をマージする最良/標準の方法は何ですか?誰もが自分のforループをロールするだけでそれをしますか?


10
JavaScriptには連想配列はありません。オブジェクトのみです。
gblazex 2010

PerlでCROSSREF同じ質問:stackoverflow.com/questions/350018/...
dreftymac

回答:


204

あなたはjqueryで呼び出すことができます $.extend

var obj1 = {a: 1, b: 2};
var obj2 = {a: 4, c: 110};

var obj3 = $.extend(obj1, obj2); 

obj1 == obj3 == {a: 4, b: 2, c: 110} // Pseudo JS

(連想配列はjsのオブジェクトです)

ここを見てください:http : //api.jquery.com/jQuery.extend/


編集: rymoが提案したように、次のように行うことをお勧めします:

obj3 = $.extend({}, obj1, obj2); 
obj3 == {a: 4, b: 2, c: 110}

ここでは、obj1(およびobj2)は変更されません。


edit2: 2018年の方法はObject.assign次のとおりです。

var obj3 = Object.assign({}, obj1, obj2); 
obj3 === {a: 4, b: 2, c: 110} // Pseudo JS

ES6で作業している場合、これはSpread Operatorで実現できます。

const obj3 = { ...obj1, ...obj2 };

54
またはいじくる避けるためにobj1、ターゲットとして空のオブジェクトを使用します$.extend({}, obj1, obj2)
rymo

はい、参照で渡されたクロージャとオブジェクトを処理するときは、rymoのアドバイスに従って、後続の操作で元のオブジェクトに影響を与えないようにしてください。
Nathan Smith

2
最新のブラウザーについては、@ manfredを使用してソリューションを確認してくださいObject.assign()。このライブラリをまだ使用していない場合は、JQueryに依存しません。
Phil

動作しますが、最初のパラメーターが変更されますので、注意が必要です。developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…を
kulpae

62

今2016年に私は最良/標準的な方法はObject.assign()
Pure Javascriptであると言います。jQueryは必要ありません。

obj1 = {a: 1, b: 2};
obj2 = {a: 4, c: 110};
obj3 = Object.assign({},obj1, obj2);  // Object {a: 4, b: 2, c: 110}

詳細、例、ポリフィルはこちら:https ://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign


obj3のタイプは何ですか?obj1がタイプIABCである場合、obj3はその後そのタイプを保持しますか?
windmaomao

49

これがPrototypeのやり方です:

Object.extend = function(destination, source) {
    for (var property in source) {
        if (source.hasOwnProperty(property)) {
            destination[property] = source[property];
        }
    }
    return destination;
};

たとえば、次のように呼び出されます。

var arr1 = { robert: "bobby", john: "jack" };
var arr2 = { elizabeth: "liz", jennifer: "jen" };

var shortnames = Object.extend(arr1,arr2);

編集:コメントでbucabayによって正しく指摘されたhasOwnProperty()チェックを追加しました


6
直接のプロパティのみをコピーすることを確認するには、テストsource.hasOwnProperty(property)が必要です。そのままでは、Object.prototypeから派生したプロパティを含むすべてのプロパティがコピーされます
bucabay

22

単純にする...

function mergeArray(array1,array2) {
  for(item in array1) {
    array2[item] = array1[item];
  }
  return array2;
}

6
hasOwnPropertyをチェックして、プロパティのコピーを回避しますarrau1.prototype
LeeGee

@LeeGeeは正しいです。そのhasOwnPropertyチェックが必要です。オブジェクトを配列として参照することも誤解を招く可能性があります(それらはオブジェクトです)。引数名は、array2が変更されていること、または新しいオブジェクトが返されることを伝える必要があります。私は答えを編集しますが、実際には、ジョナサンフィンランドの編集済み回答とほぼ同じになり、すでに修正されています。
Vaz

14

Underscoreには、extendメソッドもあります。

ソースオブジェクトのすべてのプロパティを宛先オブジェクトにコピーします。それは順番になっているので、最後のソースは前の引数の同じ名前のプロパティをオーバーライドします。

_.extend(destination, *sources) 

_.extend({name : 'moe'}, {age : 50});
=> {name : 'moe', age : 50}


6

名前は同じで値が異なる場合、プロパティを上書きしますか?

そして、元のオブジェクトの1つを永続的に変更しますか?

または、新しくマージされたオブジェクトを返しますか?

function mergedObject(obj1, obj2, force){
    for(var p in obj1) this[p]= obj1[p];
    for(var p in obj2){
        if(obj2.hasOwnProperty(p)){
            if(force || this[p]=== undefined) this[p]= obj2[p];
            else{
                n= 2;
                while(this[p+n]!== undefined)++n;
                this[p+n]= obj2[p];
            }
        }
    }
}

6

独自のExtend / Mixin関数のローリング

function extend(objects) {
    var args
        , first = Array.prototype.slice.call(arguments, 0, 1)[0]
        , second;

    if (arguments.length > 1) {
        second = Array.prototype.splice.call(arguments, 1, 1)[0];
        for (var key in second) {
            first[key] = second[key];
        }
        args = Array.prototype.slice.call(arguments, 0);
        return extend.apply(this, args);
    }

    return first;
}

...

var briansDirections = {
    step1: 'Remove pastry from wrapper.',
    step2: 'Place pastry toaster.',
    step3: 'Remove pastry from toaster and enjoy.',
};
extend(briansDirections, { step1: 'Toast Poptarts' }, { step2: 'Go ahead, toast \'em' }, { step3: 'Hey, are you sill reading this???' });

...

これは単にオブジェクトのスプラットを再帰的に拡張するだけです。また、この再帰関数はTCO(Tail-Call Optimized)であることに注意してください。これは、その戻りがそれ自体に対する最後の呼び出しであるためです。

さらに、対象のプロパティが必要になる場合があります。このケースでは、に基づいて、オブジェクト凝縮する場合がありidquantityまたは別のプロパティを。このアプローチは、それについて書かれた小さな本を持っている可能性があり、オブジェクトの並置を必要とし、非常に複雑になる可能性があります。リクエストに応じて利用できる、このための小さなライブラリを作成しました。

お役に立てれば!


4
  1. JavaScriptでは連想配列の概念はなく、オブジェクトがあります
  2. 2つのオブジェクトをマージする唯一の方法は、それらのプロパティをループし、プリミティブ型ではないそれらの値へのポインターとプリミティブ型の値を別のインスタンスにコピーすることです

8
JavaScriptのオブジェクトは連想配列として実装されているため、同じ概念が必ず存在します
Dexygen 2009年

2

2019年には、2つの適切なオプションがあります。

オブジェクトの割り当て [ ドキュメント ]

const result = Object.assign({}, baseObject, updatingObject);

オブジェクトの拡散 [ doc ]

const result = { ...baseObject, ...updatingObject};

最初のものはより安全で、より標準的で多価である傾向があります。良い長所と短所こちら



1

jqueryには、ディープコピー用のブール値があります。あなたはそのようなことをすることができます:

MergeRecursive = function(arr1, arr2){
    $.extend(true, arr1, arr2);
    return arr1;                
};

また、この関数を編集して、マージするn配列をサポートすることもできます。

ArrayMergeRecursive = function(){
     if(arguments.length < 2){
          throw new Error("ArrayMergeRecursive: Please enter two or more objects to merge!");
     }

    var arr1=arguments[0];
    for(var i=0; i<=arguments.length; i++ ){
        $.extend(true, arr1, arguments[i]);                 
    }

    return arr1;                
};

だから今できる

var arr1 = {'color': {'mycolor': 'red'}, 3: 5},
    arr2 = {4: 10, 'color': {'favorite': 'green', 0: 'blue'}},
    arr3 = ['Peter','Jhon','Demosthenes'],
    results = ArrayMergeRecursive(arr1, arr2, arr3); // (arr1, arr2 ... arrN)
console.log("Result is:", results);

0

オブジェクトの深いマージが必要でした。だから、他のすべての答えは私にはあまり役に立ちませんでした。_.extendとjQuery.extendは、私が行うような再帰的な配列がない限り、うまく機能します。しかし、それほど悪くはありません。5分でプログラムできます。

var deep_merge = function (arr1, arr2) {
    jQuery.each(arr2, function (index, element) {
        if (typeof arr1[index] === "object" && typeof element === "object") {
            arr1[index] = deep_merge(arr1[index], element);
        } else if (typeof arr1[index] === "array" && typeof element === "array") {
            arr1[index] = arr1[index].concat(element);
        } else {
            arr1[index] = element;
        }
    });
    return arr1;
}

0

jQueryで配列をマージするには、$。mergeはどうでしょうか?

var merged = $.merge([{id:3, value:'foo3'}], [{id:1, value:'foo1'}, {id:2, value:'foo2'}]);
merged[0].id == 3;
merged[0].value == 'foo3';
merged[1].id == 1;
merged[1].value == 'foo1';
merged[2].id == 2;
merged[2].value == 'foo2';

0

再帰的ソリューション(オブジェクトの配列も拡張)+チェックされたnull

var addProps = function (original, props) {
    if(!props) {
        return original;
    }
    if (Array.isArray(original)) {
        original.map(function (e) {
            return addProps(e, props)
        });
        return original;
    }
    if (!original) {
        original = {};
    }
    for (var property in props) {
        if (props.hasOwnProperty(property)) {
            original[property] = props[property];
        }
    }
    return original;
};

テスト

console.log(addProps([{a: 2}, {z: 'ciao'}], {timestamp: 13}));
console.log(addProps({single: true}, {timestamp: 13}));
console.log(addProps({}, {timestamp: 13}));
console.log(addProps(null, {timestamp: 13}));

[ { a: 2, timestamp: 13 }, { z: 'ciao', timestamp: 13 } ]
{ single: true, timestamp: 13 }
{ timestamp: 13 }
{ timestamp: 13 }

Node JSでこれを使用してみましたObject.getOwnPropertyNames is not a functionが、アプリがクラッシュします。
Legoless、

私はこれをplv8 PostgreSQL拡張機能内の古いバージョンのv8エンジンで使用しています。そしてそれはブラウザで動作します。JSエンジンで「hasOwnProperty」と同等のことを行う方法を見つけてください。その後、このロジックを再利用できます。
sscarduzio 2016年

0

これが最良の解決策です。

obj1.unshift.apply( obj1, obj2 );

また、obj1ループ内で問題なく成長できます。(obj2動的であると言いましょう)

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