523 Stimmen

Lodash - Unterschied zwischen .extend() / .assign() und .merge()

In der Lodash-Bibliothek kann jemand eine bessere Erklärung für merge und extend / assign bereitstellen.

Es ist eine einfache Frage, aber die Antwort entzieht sich mir dennoch.

628voto

Shital Shah Punkte 54846

So funktioniert erweitern/zuweisen: Für jedes Attribut in der Quelle wird dessen Wert unverändert in das Ziel kopiert. Wenn die Attributwerte selbst Objekte sind, findet keine rekursive Traversierung ihrer Attribute statt. Das gesamte Objekt wird aus der Quelle genommen und im Ziel gesetzt.

So funktioniert verschmelzen: Für jedes Attribut in der Quelle wird überprüft, ob das Attribut selbst ein Objekt ist. Falls ja, wird rekursiv nach unten gegangen und versucht, die Eigenschaften des untergeordneten Objekts von der Quelle auf das Ziel abzubilden. Im Wesentlichen verschmelzen wir also die Objekthierarchie von der Quelle zum Ziel. Während es bei erweitern/zuweisen einfach eine Kopie der Eigenschaften von der Quelle zum Ziel auf einer Ebene ist.

Hier ist ein einfaches JSBin-Beispiel, das dies kristallklar macht: http://jsbin.com/uXaqIMa/2/edit?js,console

Hier ist eine ausführlichere Version, die auch ein Array im Beispiel enthält: http://jsbin.com/uXaqIMa/1/edit?js,console

607voto

Nate Punkte 12396

Lodash Version 3.10.1

Verglichene Methoden

  • _.merge(object, [Quellen], [Anpasser], [thisArg])
  • _.assign(object, [Quellen], [Anpasser], [thisArg])
  • _.extend(object, [Quellen], [Anpasser], [thisArg])
  • _.defaults(object, [Quellen])
  • _.defaultsDeep(object, [Quellen])

Ähnlichkeiten

  • Keiner von ihnen funktioniert bei Arrays wie man erwarten könnte
  • _.extend ist ein Alias für _.assign, also sind sie identisch
  • Alle scheinen das Zielobjekt (erstes Argument) zu modifizieren
  • Alle behandeln null auf die gleiche Weise

Unterschiede

  • _.defaults und _.defaultsDeep verarbeiten die Argumente in umgekehrter Reihenfolge im Vergleich zu den anderen (obwohl das erste Argument immer noch das Zielobjekt ist)
  • _.merge und _.defaultsDeep werden Unterobjekte zusammenführen und die anderen werden auf der Basisebene überschreiben
  • Nur _.assign und _.extend werden einen Wert mit undefined überschreiben

Tests

Sie alle behandeln Elemente auf der Basis in ähnlicher Weise.

_.assign      ({}, { a: 'a' }, { a: 'bb' }) // => { a: "bb" }
_.merge       ({}, { a: 'a' }, { a: 'bb' }) // => { a: "bb" }
_.defaults    ({}, { a: 'a' }, { a: 'bb' }) // => { a: "a"  }
_.defaultsDeep({}, { a: 'a' }, { a: 'bb' }) // => { a: "a"  }

_.assign behandelt undefined, aber die anderen werden es überspringen

_.assign      ({}, { a: 'a'  }, { a: undefined }) // => { a: undefined }
_.merge       ({}, { a: 'a'  }, { a: undefined }) // => { a: "a" }
_.defaults    ({}, { a: undefined }, { a: 'bb' }) // => { a: "bb" }
_.defaultsDeep({}, { a: undefined }, { a: 'bb' }) // => { a: "bb" }

Sie alle behandeln null auf die gleiche Weise

_.assign      ({}, { a: 'a'  }, { a: null }) // => { a: null }
_.merge       ({}, { a: 'a'  }, { a: null }) // => { a: null }
_.defaults    ({}, { a: null }, { a: 'bb' }) // => { a: null }
_.defaultsDeep({}, { a: null }, { a: 'bb' }) // => { a: null }

Aber nur _.merge und _.defaultsDeep werden Unterobjekte zusammenführen

_.assign      ({}, {a:{a:'a'}}, {a:{b:'bb'}}) // => { "a": { "b": "bb" }}
_.merge       ({}, {a:{a:'a'}}, {a:{b:'bb'}}) // => { "a": { "a": "a", "b": "bb" }}
_.defaults    ({}, {a:{a:'a'}}, {a:{b:'bb'}}) // => { "a": { "a": "a" }}
_.defaultsDeep({}, {a:{a:'a'}}, {a:{b:'bb'}}) // => { "a": { "a": "a", "b": "bb" }}

Und keiner von ihnen wird Arrays zusammenführen, anscheinend

_.assign      ({}, {a:['a']}, {a:['bb']}) // => { "a": [ "bb" ] }
_.merge       ({}, {a:['a']}, {a:['bb']}) // => { "a": [ "bb" ] }
_.defaults    ({}, {a:['a']}, {a:['bb']}) // => { "a": [ "a"  ] }
_.defaultsDeep({}, {a:['a']}, {a:['bb']}) // => { "a": [ "a"  ] }

Alle modifizieren das Zielobjekt

a={a:'a'}; _.assign      (a, {b:'bb'}); // a => { a: "a", b: "bb" }
a={a:'a'}; _.merge       (a, {b:'bb'}); // a => { a: "a", b: "bb" }
a={a:'a'}; _.defaults    (a, {b:'bb'}); // a => { a: "a", b: "bb" }
a={a:'a'}; _.defaultsDeep(a, {b:'bb'}); // a => { a: "a", b: "bb" }

Keiner funktioniert wirklich wie erwartet bei Arrays

Hinweis: Wie @Mistic herausgestellt hat, behandelt Lodash Arrays als Objekte, bei denen die Schlüssel den Index im Array darstellen.

_.assign      ([], ['a'], ['bb']) // => [ "bb" ]
_.merge       ([], ['a'], ['bb']) // => [ "bb" ]
_.defaults    ([], ['a'], ['bb']) // => [ "a"  ]
_.defaultsDeep([], ['a'], ['bb']) // => [ "a"  ]

_.assign      ([], ['a','b'], ['bb']) // => [ "bb", "b" ]
_.merge       ([], ['a','b'], ['bb']) // => [ "bb", "b" ]
_.defaults    ([], ['a','b'], ['bb']) // => [ "a", "b"  ]
_.defaultsDeep([], ['a','b'], ['bb']) // => [ "a", "b"  ]

84voto

samz Punkte 1572

Ein weiterer Unterschied, auf den geachtet werden muss, ist der Umgang mit undefined Werten:

mergeInto = { a: 1}
toMerge = {a : undefined, b:undefined}
lodash.extend({}, mergeInto, toMerge) // => {a: undefined, b:undefined}
lodash.merge({}, mergeInto, toMerge)  // => {a: 1, b:undefined}

Also wird merge keine undefined Werte in definierte Werte zusammenführen.

24voto

epeleg Punkte 9853

Es könnte auch hilfreich sein, zu berücksichtigen, was sie aus semantischer Sicht tun:

_.assign

   weist die Werte der Eigenschaften seines zweiten Parameters und so weiter zu,
   als Eigenschaften mit demselben Namen des ersten Parameters. (flache Kopie & Überschreibung)

_.merge

   merge ist wie assign, weist jedoch keine Objekte zu, sondern repliziert sie stattdessen.
  (Tiefe Kopie)

_.defaults

   stellt Standardwerte für fehlende Werte bereit.
   wird also nur Werte für Schlüssel zuweisen, die im Quellobjekt noch nicht existieren.

_.defaultsDeep

   funktioniert wie _defaults, aber wie merge wird es Objekte nicht einfach kopieren
   und stattdessen Rekursion verwenden.

Ich glaube, dass es hilfreich ist, diese Methoden aus semantischer Sicht zu betrachten, um besser "erraten" zu können, wie sich die verschiedenen Szenarien von existierenden und nicht existierenden Werten verhalten würden.

6voto

mbao01 Punkte 168

Wenn Sie eine Tiefenkopie ohne Überschreiben wünschen und trotzdem die gleiche obj-Referenz beibehalten möchten

obj = _.assign(obj, _.merge(obj, [source]))

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