Objekte zusammenführen (assoziative Arrays)

147

Was ist die beste / Standardmethode zum Zusammenführen von zwei assoziativen Arrays in JavaScript? Tut jeder das nur, indem er seine eigene forSchleife rollt ?

Wilhelm
quelle
10
Es gibt übrigens keine assoziativen Arrays in Javascript, nur Objekte.
Gblazex
Crossref gleiche Frage in Perl: stackoverflow.com/questions/350018/…
dreftymac
Assoziative Arrays in Javascript: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Chris Martin

Antworten:

204

mit jquery können Sie anrufen $.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

(Assoc. Arrays sind Objekte in js)

Schauen Sie hier: http://api.jquery.com/jQuery.extend/


edit: Wie von rymo vorgeschlagen, ist es besser, es so zu machen:

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

Wie hier bleiben obj1 (und obj2) unverändert.


edit2: Im Jahr 2018 ist der Weg dazu Object.assign:

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

Wenn Sie mit ES6 arbeiten, kann dies mit dem Spread Operator erreicht werden :

const obj3 = { ...obj1, ...obj2 };
Kulpae
quelle
54
oder um obj1$.extend({}, obj1, obj2)
Mist
Ja, wenn Sie sich mit Verschlüssen und Objekten befassen, die als Referenz übergeben wurden, befolgen Sie den Rat von rymo, um zu vermeiden, dass das ursprüngliche Objekt für nachfolgende Operationen beeinträchtigt wird.
Nathan Smith
2
Überprüfen Sie für moderne Browser die Lösung von @manfred using Object.assign(), die nicht auf JQuery basiert , wenn Sie die Bibliothek nicht bereits verwenden.
Phil
Es funktioniert, aber es ändert den ersten Parameter und das ist etwas, das Sie beachten müssen. Siehe developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
kulpae
62

Jetzt im Jahr 2016 würde ich sagen, dass der beste / Standardweg Object.assign ()
Pure Javascript ist. Es wird keine jQuery benötigt.

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

Weitere Informationen, Beispiele und Polyfill finden Sie hier:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

Manfred
quelle
Was ist der Typ für obj3? Was ist, wenn obj1 vom Typ IABC ist? Wird obj3 diesen Typ danach beibehalten?
Windmaomao
49

So macht es Prototype:

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

genannt als zum Beispiel:

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

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

EDIT : hinzugefügt hasOwnProperty () überprüfen , wie richtig durch bucabay in den Kommentaren darauf hingewiesen ,

Jonathan Fingland
quelle
6
Sie benötigen die Testquelle.hasOwnProperty (Eigenschaft), um sicherzustellen, dass Sie nur die unmittelbaren Eigenschaften kopieren. So wie es ist, könnte dies alle Eigenschaften kopieren, einschließlich der von Object.prototype
bucabay
22

Halte es einfach...

function mergeArray(array1,array2) {
  for(item in array1) {
    array2[item] = array1[item];
  }
  return array2;
}
Chris Scerbo
quelle
6
Sie müssen hasOwnProperty überprüfen, um das Kopieren von Eigenschaften auf demarrau1.prototype
LeeGee
@ LeeGee ist richtig. Sie brauchen diesen hasOwnPropertyScheck. Das Verweisen auf die Objekte als Arrays ist ebenfalls irreführend (sie sind Objekte). Die Arg-Namen sollten vermitteln, dass Array2 mutiert ist, oder ein neues Objekt sollte zurückgegeben werden. Ich würde die Antwort bearbeiten, aber tatsächlich würde es fast genau Jonathan Finglands bearbeitete Antwort werden, die bereits korrigiert wurde.
Vaz
14

Unterstrich hat auch eine Erweiterungsmethode:

Kopieren Sie alle Eigenschaften in den Quellobjekten in das Zielobjekt. Es ist in der richtigen Reihenfolge, sodass die letzte Quelle gleichnamige Eigenschaften in vorherigen Argumenten überschreibt.

_.extend(destination, *sources) 

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

Im Dojo wäre die "Zusammenführung" der 2 Objekte / Arrays lang.mixin(destination, source)- Sie können auch mehrere Quellen zu einem Ziel mischen usw. - Einzelheiten finden Sie in der Referenz der Mixin-Funktion .

Alex Martelli
quelle
6

Möchten Sie eine Eigenschaft überschreiben, wenn die Namen identisch sind, die Werte jedoch nicht?

Und möchten Sie eines der Originalobjekte dauerhaft ändern?

oder möchten Sie ein neues zusammengeführtes Objekt zurückgeben?

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];
            }
        }
    }
}
kennebec
quelle
6

Rolling Your Own Extend / Mixin- Funktion

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???' });

...

Dies erweitert einfach einen Teil der Objekte rekursiv. Beachten Sie außerdem, dass diese rekursive Funktion TCO ( Tail-Call Optimized ) ist, da ihre Rückgabe der letzte Aufruf an sich selbst ist.

Darüber hinaus möchten Sie möglicherweise gezielte Eigenschaften . In diesem Fall können Sie Objekte kondensieren auf der Basis id, quantityoder eine andere Eigenschaft. Dieser Ansatz könnte ein kleines Buch darüber schreiben und erfordert eine Gegenüberstellung von Objekten und kann sehr komplex werden. Ich habe dafür eine kleine Bibliothek geschrieben, die auf Anfrage erhältlich ist.

Hoffe das hilft!

Cody
quelle
4
  1. In Javascript gibt es keine Vorstellung von einem assoziativen Array, es gibt Objekte
  2. Die einzige Möglichkeit, zwei Objekte zusammenzuführen, besteht darin, eine Schleife für ihre Eigenschaften durchzuführen und Zeiger auf ihre Werte zu kopieren, die keine primitiven Typen sind, und Werte für primitive Typen auf eine andere Instanz
Sergey Ilinsky
quelle
8
Objekte in Javascript werden als assoziative Arrays implementiert, daher gibt es sicherlich den Begriff desselben
Dexygen
2

Im Jahr 2019 haben Sie 2 gute Möglichkeiten:

Objektzuweisung [ doc ]

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

Objektverbreitung [ doc ]

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

Der erste ist tendenziell sicherer, standardisierter und polyvalenter. Ein gutes Für und Wider hier

VincentPerrin.com
quelle
1

Yahoo UI (YUI) hat auch eine Hilfsfunktion dafür:

http://developer.yahoo.com/yui/examples/yahoo/yahoo_merge.html

YAHOO.namespace('example');

YAHOO.example.set1 = { foo : "foo" };
YAHOO.example.set2 = { foo : "BAR", bar : "bar" };
YAHOO.example.set3 = { foo : "FOO", baz : "BAZ" };

var Ye = YAHOO.example;

var merged = YAHOO.lang.merge(Ye.set1, Ye.set2, Ye.set3);
Ben Walding
quelle
1

jquery hat einen Booleschen Wert für Deep Copy. Sie könnten so etwas tun:

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

Sie können diese Funktion auch bearbeiten, um das Zusammenführen von n-Arrays zu unterstützen.

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

Jetzt können Sie es also tun

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);
Demosthenes
quelle
0

Ich brauchte eine tiefe Objektverschmelzung. Alle anderen Antworten haben mir also nicht sehr geholfen. _.extend und jQuery.extend funktionieren gut, es sei denn, Sie haben ein rekursives Array wie ich. Aber es ist nicht so schlimm, Sie können es in fünf Minuten programmieren:

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;
}
Rasmus
quelle
0

Um Arrays in jQuery zusammenzuführen, was ist mit $ .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';
Rogério R. Alcântara
quelle
0

Rekursive Lösung (erweitert auch Arrays von Objekten) + null geprüft

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

Tests

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 }
sscarduzio
quelle
Ich habe versucht, dies mit Node JS zu verwenden, aber Object.getOwnPropertyNames is not a functiondie App wird abstürzen.
Legoless
Ich verwende dies mit einer alten v8-Engine in der plv8 PostgreSQL-Erweiterung. Und es funktioniert in Browsern. Finden Sie einfach einen Weg in Ihrer JS-Engine, um das Gleiche wie "hasOwnProperty" zu tun. Dann können Sie diese Logik wiederverwenden.
sscarduzio
0

Hier ist die beste Lösung.

obj1.unshift.apply( obj1, obj2 );

Außerdem obj1kann in einer Schleife ohne Probleme wachsen. (sagen wir obj2ist dynamisch)

bilen
quelle