Zwei Objekte ohne Überschreiben zusammenführen

Lesezeit: 4 Minuten

Ich habe ein defaultObject wie folgt:

var default = {
    abc: "123",
    def: "456",
    ghi: {
       jkl: "789",
       mno: "012"
    }
};

Und ich habe noch einen wie:

var values = {
    abc: "zzz",
    ghi: {
       jkl: "yyy",
    }
};

Wie kann ich diese 2 Objekte mit dem folgenden Ergebnis zusammenführen (kein Überschreiben)?

var values = {
    abc: "zzz",
    def: "456",
    ghi: {
       jkl: "yyy",
       mno: "012"
    }
};

(Ich möchte das Standardobjekt nicht ändern!)

Benutzeravatar von Oriol
Oriol

Für diejenigen, die jQuery nicht verwenden, kommt hier eine Vanilla-js-Lösung.

Lösung:

function extend (target) {
    for(var i=1; i<arguments.length; ++i) {
        var from = arguments[i];
        if(typeof from !== 'object') continue;
        for(var j in from) {
            if(from.hasOwnProperty(j)) {
                target[j] = typeof from[j]==='object'
                ? extend({}, target[j], from[j])
                : from[j];
            }
        }
    }
    return target;
}

Komprimiert (mit Closure-Compiler):

Nur 199 Zeichen!

var extend=function e(c){for(var d=1;d<arguments.length;++d){var a=arguments[d];if("object"===typeof a)for(var b in a)a.hasOwnProperty(b)&&(c[b]="object"===typeof a[b]?e({},c[b],a[b]):a[b])}return c}

Wie benutzt man:

extend(target, obj1, obj2); // returns target

Wenn Sie nur zusammenführen möchten, verwenden Sie

var merged = extend({}, obj1, obj2);

Merkmale:

  • Es betrachtet nicht den Prototyp von Objekten.
  • Ignoriert Nicht-Objekte.
  • Es ist rekursiv, um Eigenschaften zusammenzuführen, die Objekte sind.
  • Objekte, auf die verwiesen wird in targetDie Eigenschaften von werden, wenn sie erweitert werden, durch neue ersetzt, und die ursprünglichen werden nicht geändert.
  • Bei gleichen Eigenschaftsnamen ist der zusammengeführte Wert die Zusammenführung der Objekte nach dem letzten (in der Reihenfolge der Argumente) Nicht-Objektwert. Oder, wenn letzteres kein Objekt ist, es selbst.

Beispiele:

extend({}, {a:1}, {a:2});            // {a:2}
extend({}, {a:1}, {b:2});            // {a:1, b:2}
extend({}, {a: {b:1}}, {a: {b:2}});  // {a: {b:2}}
extend({}, {a: {b:1}}, {a: {c:2}});  // {a: {b:2, c:2}}
extend({}, {a: {a:1}}, {a: {b:2}}, {a: 'whatever non object'});
    // {a: "whatever non object"}
extend({}, {a: {a:1}}, {a: {b:2}}, {a: 'whatever non object'}, {a: {c:3}},{a: {d:4}});
    // {a: {c:3, d:4}}

Warnung:

Seien Sie sich bewusst, dass ein Browser, der nicht schlau genug ist, in einer Endlosschleife gefangen sein könnte:

var obj1={},
    obj2={};
obj1.me=obj1;
obj2.me=obj2;
extend({},obj1,obj2);

Wenn der Browser schlau genug ist, kann er einen Fehler ausgeben oder zurückkehren {me: undefined}oder Wasauchimmer.

Beachten Sie, dass diese Warnung auch gilt, wenn Sie jQuery verwenden $.extend.

  • Ein Problem. Es konvertiert Arrays in Objekte.

    – Benutzer3123032

    30. August um 14:20 Uhr

Benutzeravatar von adeneo
adeneo

Da ES2015 jetzt in allen modernen Browsern unterstützt wird, ist die native Object.assign kann zum Erweitern von Objekten verwendet werden

Object.assign({}, _default, values)

Objektzuweisung

Beachten Sie, dass default ist ein reserviertes Schlüsselwort und kann nicht als Variablenname verwendet werden


Die ursprüngliche Antwort, geschrieben im Jahr 2013:

Da dies mit jQuery getaggt ist, könnten Sie verwenden $.erweitern für eine einfache browserübergreifende Lösung

var temp = {};
$.extend(true, temp, _default, values);
values = temp;

  • Aber das wird mein Standard-‘default_array’ ändern und ich will es nicht, weil es eine globale Variable ist …

    – Verstärker

    15. Dezember 2013 um 1:21 Uhr

  • @amp – das lässt sich leicht vermeiden, indem man ein temporäres Objekt verwendet.

    – adeneo

    15. Dezember 2013 um 1:29 Uhr

  • Das geht nicht, ghi werden überschrieben, nicht zusammengeführt.

    – Nate

    12. Juni 2019 um 4:04 Uhr

  • Ja, vorhandene Objekte werden in verschachteltem JSON entfernt

    – Phaneendra Charyulu Kanduri

    2. Juni 2021 um 16:42 Uhr

Auch wenn Sie mit ES6 zufrieden sind:

Object.assign({}, default, values)

  • Wird immer noch außer Kraft gesetzt, wenn der Wert standardmäßig vorhanden ist

    – Michael Heuberger

    27. Mai 2021 um 7:45 Uhr

Eine andere Möglichkeit wäre, den Wert einfach standardmäßig zu erweitern (anstatt umgekehrt, was die Standardeinstellung überschreiben würde).

Object.assign(value, default) // values of default overrides value
default = value // reset default to value

Der Vorbehalt hier ist, dass auch der Inhalt des Werts geändert wird. Der Vorteil ist, dass keine Bibliothek erforderlich ist und einfacher als die obige Plain-Vanilla-Lösung.

Meine Version, die auf Oriols Antwort basiert, fügt eine Überprüfung für Arrays hinzu, damit Arrays nicht in lustige {‘0’: …, ‘1’: …} Dinge umgewandelt werden

function extend (target) {
  for(var i=1; i<arguments.length; ++i) {
    var from = arguments[i];
    if(typeof from !== 'object') continue;
    for(var j in from) {
      if(from.hasOwnProperty(j)) {
        target[j] = typeof from[j]==='object' && !Array.isArray(from[j])
          ? extend({}, target[j], from[j])
          : from[j];
      }
    }
  }
  return target;
}

Benutzeravatar von Henric Malmberg
Henric Malberg

Ich fand, dass der einfachste Weg dazu die Verwendung ist mergeWith() von lodash ( https://lodash.com/docs/4.17.15#mergeWith ), die eine Anpassungsfunktion akzeptiert, die entscheidet, was mit jeder Eigenschaftszusammenführung geschehen soll. Hier ist eine, die rekursiv ist:

const mergeFunction = (objValue, srcValue) => {
  if (typeof srcValue === 'object') {
    _.mergeWith(objValue, srcValue, mergeFunction)
  } else if (objValue) {
    return objValue
  } else {
    return srcValue
  }
}

1435740cookie-checkZwei Objekte ohne Überschreiben zusammenführen

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy