3287 Stimmen

Wie kann ich die Eigenschaften von zwei JavaScript-Objekten dynamisch zusammenführen?

Ich muss in der Lage sein, zwei (sehr einfache) JavaScript-Objekte zur Laufzeit zu verschmelzen. Zum Beispiel würde ich gerne:

var obj1 = { food: 'pizza', car: 'ford' }
var obj2 = { animal: 'dog' }

obj1.merge(obj2);

//obj1 now has three properties: food, car, and animal

Gibt es eine eingebaute Möglichkeit, dies zu tun? Ich brauche keine Rekursion, und ich muss nicht Funktionen zusammenführen, nur Methoden auf flache Objekte.

0 Stimmen

Es ist erwähnenswert diese Antwort auf eine ähnliche Frage , die zeigt, wie man "eine Ebene tiefer" zusammenführt. Das heißt, es werden Werte mit doppelten Schlüsseln zusammengeführt (anstatt den ersten Wert mit dem zweiten zu überschreiben), aber es wird nicht weiter rekursiert als das. IMHO ist es ein guter, sauberer Code für diese Aufgabe.

0 Stimmen

Übrigens führen die ersten paar Antworten eine "oberflächliche" Zusammenführung durch: Wenn derselbe Schlüssel sowohl in obj1 als auch in obj2 vorhanden ist, wird der Wert in obj2 beibehalten, der Wert in obj1 wird gelöscht. Wenn z.B. das Beispiel der Frage var obj2 = { animal: 'dog', food: 'bone' }; wäre die Verschmelzung { food: 'bone', car: 'ford', animal: 'dog' } . Wenn Sie mit "verschachtelten Daten" arbeiten und eine "tiefe Zusammenführung" wünschen, suchen Sie nach Antworten, die "tiefe Zusammenführung" oder "Rekursion" erwähnen. Wenn Sie Werte haben, die arrays verwenden Sie dann die Option "arrayMerge" von github "TehShrike/deepmerge", wie erwähnt aquí .

4058voto

John Millikin Punkte 190278

ECMAScript 2018 Standard-Methode

Sie würden verwenden Objektausbreitung :

let merged = {...obj1, ...obj2};

merged ist nun die Vereinigung von obj1 y obj2 . Eigenschaften in obj2 überschreiben die in obj1 .

/** There's no limit to the number of objects you can merge.
 *  Later properties overwrite earlier properties with the same name. */
const allRules = {...obj1, ...obj2, ...obj3};

Hier ist auch die MDN-Dokumentation für diese Syntax. Wenn Sie babel verwenden, benötigen Sie die babel-plugin-transform-object-rest-spread Plugin, damit es funktioniert.

ECMAScript 2015 (ES6) Standardverfahren

/* For the case in question, you would do: */
Object.assign(obj1, obj2);

/** There's no limit to the number of objects you can merge.
 *  All objects get merged into the first object. 
 *  Only the object in the first argument is mutated and returned.
 *  Later properties overwrite earlier properties with the same name. */
const allRules = Object.assign({}, obj1, obj2, obj3, etc);

(siehe MDN JavaScript-Referenz )


Methode für ES5 und frühere Versionen

for (var attrname in obj2) { obj1[attrname] = obj2[attrname]; }

Beachten Sie, dass dies einfach alle Attribute von obj2 a obj1 was vielleicht nicht das ist, was Sie wollen, wenn Sie weiterhin die unveränderte obj1 .

Wenn Sie ein Framework verwenden, das Ihre Prototypen durcheinanderwirbelt, müssen Sie sich mit Prüfungen wie hasOwnProperty aber dieser Code wird in 99 % der Fälle funktionieren.

Beispielfunktion:

/**
 * Overwrites obj1's values with obj2's and adds obj2's if non existent in obj1
 * @param obj1
 * @param obj2
 * @returns obj3 a new object based on obj1 and obj2
 */
function merge_options(obj1,obj2){
    var obj3 = {};
    for (var attrname in obj1) { obj3[attrname] = obj1[attrname]; }
    for (var attrname in obj2) { obj3[attrname] = obj2[attrname]; }
    return obj3;
}

127 Stimmen

Dies funktioniert nicht, wenn die Objekte gleichnamige Attribute haben und Sie die Attribute auch zusammenführen möchten.

84 Stimmen

Damit wird nur eine oberflächliche Kopie/Zusammenführung durchgeführt. Hat das Potenzial, eine Menge von Elementen zu verschlucken.

62 Stimmen

+1 dafür, dass du anerkennst, dass einige arme Seelen gezwungen sind, Frameworks zu verwenden, die ihre Prototypen vollscheißen...

1242voto

Avdi Punkte 18202

JQuery hat auch ein Dienstprogramm für diese Aufgabe: http://api.jquery.com/jQuery.extend/ .

Entnommen aus der jQuery-Dokumentation:

// Merge options object into settings object
var settings = { validate: false, limit: 5, name: "foo" };
var options  = { validate: true, name: "bar" };
jQuery.extend(settings, options);

// Now the content of settings object is the following:
// { validate: true, limit: 5, name: "bar" }

Der obige Code mutiert die bestehendes Objekt namens settings .


Wenn Sie eine neues Objekt ohne eines der beiden Argumente zu ändern, verwenden Sie dies:

var defaults = { validate: false, limit: 5, name: "foo" };
var options = { validate: true, name: "bar" };

/* Merge defaults and options, without modifying defaults */
var settings = $.extend({}, defaults, options);

// The content of settings variable is now the following:
// {validate: true, limit: 5, name: "bar"}
// The 'defaults' and 'options' variables remained the same.

176 Stimmen

Aber Vorsicht: Die Variable "settings" wird dabei verändert. jQuery gibt keine neue Instanz zurück. Der Grund dafür (und für die Namensgebung) ist, dass .extend() entwickelt wurde, um Objekte zu erweitern, und nicht, um Dinge zusammenzuwürfeln. Wenn Sie ein neues Objekt wollen (z.B. Einstellungen sind Standardwerte, die Sie nicht ändern wollen), können Sie immer jQuery.extend({}, Einstellungen, Optionen) verwenden;

32 Stimmen

Wohlgemerkt, jQuery.extend hat auch eine tiefe (boolesche) Einstellung. jQuery.extend(true,settings,override) Dies ist wichtig, wenn eine Eigenschaft in den Einstellungen ein Objekt enthält und die Überschreibung nur einen Teil dieses Objekts enthält. Anstatt die nicht übereinstimmenden Eigenschaften zu entfernen, wird die tiefe Einstellung nur dort aktualisiert, wo sie vorhanden ist. Der Standardwert ist false.

392voto

NanoWizard Punkte 1949

El Harmonie ECMAScript 2015 (ES6) gibt an. Object.assign die dies tun wird.

Object.assign(obj1, obj2);

Die aktuelle Browserunterstützung ist besser werden aber wenn Sie für Browser entwickeln, die keine Unterstützung haben, können Sie eine Polyfill .

49 Stimmen

Beachten Sie, dass dies nur eine oberflächliche Zusammenführung ist.

0 Stimmen

Ich denke inzwischen Object.assign hat eine ziemlich gute Abdeckung: kangax.github.io/compat-table/es6/

17 Stimmen

Dies sollte nun die richtige Antwort sein. Heutzutage kompilieren die Leute ihren Code so, dass er mit dem seltenen Browser (IE11) kompatibel ist, der diese Art von Dingen nicht unterstützt. Nebenbemerkung: Wenn Sie obj2 nicht zu obj1 hinzufügen möchten, können Sie ein neues Objekt mit Object.assign({}, obj1, obj2)

299voto

Ich habe nach Code zum Zusammenführen von Objekteigenschaften gegoogelt und bin hier gelandet. Da es jedoch keinen Code für rekursive Zusammenführung gab, habe ich ihn selbst geschrieben. (Vielleicht jQuery erweitern ist rekursiv BTW?) Wie auch immer, hoffentlich jemand anderes wird es auch nützlich finden.

(Jetzt verwendet der Code nicht mehr Object.prototype :)

Código

/*
* Recursively merge properties of two objects 
*/
function MergeRecursive(obj1, obj2) {

  for (var p in obj2) {
    try {
      // Property in destination object set; update its value.
      if ( obj2[p].constructor==Object ) {
        obj1[p] = MergeRecursive(obj1[p], obj2[p]);

      } else {
        obj1[p] = obj2[p];

      }

    } catch(e) {
      // Property in destination object not set; create it and set its value.
      obj1[p] = obj2[p];

    }
  }

  return obj1;
}

Ein Beispiel

o1 = {  a : 1,
        b : 2,
        c : {
          ca : 1,
          cb : 2,
          cc : {
            cca : 100,
            ccb : 200 } } };

o2 = {  a : 10,
        c : {
          ca : 10,
          cb : 20, 
          cc : {
            cca : 101,
            ccb : 202 } } };

o3 = MergeRecursive(o1, o2);

Erzeugt das Objekt o3 wie

o3 = {  a : 10,
        b : 2,
        c : {
          ca : 10,
          cb : 20,
          cc : { 
            cca : 101,
            ccb : 202 } } };

11 Stimmen

Schön, aber ich würde zuerst eine Tiefenkopie der Objekte erstellen. Auf diese Weise würde auch o1 geändert werden, da die Objekte per Referenz übergeben werden.

181voto

Industrial Punkte 38579

Beachten Sie, dass underscore.js 's extend -Verfahren tut dies in einem Einzeiler:

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

39 Stimmen

Dieses Beispiel ist in Ordnung, da Sie mit anonymen Objekten zu tun haben, aber wenn dies nicht der Fall ist, dann ist webmat's Kommentar in der jQuery-Antwort Warnung vor Mutationen gilt hier, da Unterstrich auch mutiert das Zielobjekt . Wie die jQuery-Antwort, um dies zu tun mutation-free nur in ein leeres Objekt zusammenführen: _({}).extend(obj1, obj2);

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X