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


Antworten:


583

Hier ist , wie extend/ assignWerke: Für jede Eigenschaft in Quelle, kopieren Sie den Wert zum Ziel , wie sie ist. Wenn Eigenschaftswerte selbst Objekte sind, erfolgt keine rekursive Durchquerung ihrer Eigenschaften. Das gesamte Objekt wird aus der Quelle entnommen und auf das Ziel gesetzt.

So mergefunktioniert es: Überprüfen Sie für jede Eigenschaft in der Quelle, ob diese Eigenschaft selbst ein Objekt ist. Wenn dies der Fall ist, gehen Sie rekursiv nach unten und versuchen Sie, untergeordnete Objekteigenschaften von der Quelle zum Ziel zuzuordnen. Im Wesentlichen führen wir die Objekthierarchie von der Quelle zum Ziel zusammen. Während für extend/ assignist es eine einfache einstufige Kopie der Eigenschaften von der Quelle zum Ziel.

Hier ist eine einfache JSBin, die dies kristallklar macht: http://jsbin.com/uXaqIMa/2/edit?js,console

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


16
Ein wichtiger Unterschied scheint zu sein, dass, während _.merge ein neues zusammengeführtes Objekt zurückgibt, _.extend das Zielobjekt an Ort und Stelle mutiert
letronje

69
Beide scheinen das Zielobjekt zu mutieren, unabhängig davon, was sie zurückgeben.
Jason Rice

7
Es scheint auch, dass _.extend Mitglieder des Zielobjekts blockiert, wenn sie nicht im Quellobjekt vorhanden sind, was für mich überraschend ist.
Jason Rice

5
@ JasonRice Sie werden nicht überfallen. Zum Beispiel wird in dieser Geige die "a" -Eigenschaft nicht überlastet . Es ist wahr, dass nach dem Erweitern dest ["p"] ["y"] nicht mehr existiert. Dies liegt daran, dass vor dem Erweitern src und dest beide eine "p" -Eigenschaft hatten, sodass die "p" -Eigenschaft von dest vollständig überschrieben wird durch die "p" -Eigenschaft von src (sie sind jetzt genau das gleiche Objekt).
Kevin Wheeler

14
Um klar zu sein, modifizieren / überschreiben beide Methoden das erste Argument durch Bezugnahme. Wenn Sie also ein neues Objekt aus der resultierenden Zusammenführung möchten, übergeben Sie am besten ein Objektliteral. var combined = merge({}, src, dest)
Jon Jaques

534

Lodash Version 3.10.1

Methoden verglichen

  • _.merge(object, [sources], [customizer], [thisArg])
  • _.assign(object, [sources], [customizer], [thisArg])
  • _.extend(object, [sources], [customizer], [thisArg])
  • _.defaults(object, [sources])
  • _.defaultsDeep(object, [sources])

Ähnlichkeiten

  • Keiner von ihnen arbeitet erwartungsgemäß mit Arrays
  • _.extendist ein Alias ​​für _.assign, also sind sie identisch
  • Alle scheinen das Zielobjekt zu modifizieren (erstes Argument)
  • Alle von ihnen behandeln nulldas gleiche

Unterschiede

  • _.defaultsund _.defaultsDeepverarbeitet die Argumente in umgekehrter Reihenfolge im Vergleich zu den anderen (obwohl das erste Argument immer noch das Zielobjekt ist)
  • _.mergeund _.defaultsDeepwerden untergeordnete Objekte zusammenführen und die anderen werden auf der Stammebene überschrieben
  • Nur _.assignund _.extendüberschreibt einen Wert mitundefined

Tests

Sie alle behandeln Mitglieder an der Wurzel auf ähnliche 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"  }

_.assignGriffe, undefinedaber 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 nulldas gleiche

_.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 _.mergeund _.defaultsDeepuntergeordnete Objekte 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, wie es scheint

_.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 ändern 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 auf Arrays

Hinweis: Wie @Mistic hervorhob, behandelt Lodash Arrays als Objekte, bei denen die Schlüssel der Index für das Array sind.

_.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"  ]

32
Es führt Arrays genau so zusammen, wie es Objekte zusammenführt, da Arrays Objekte mit numerischen Schlüsseln sind. Ich bin damit einverstanden, dass man erwarten würde, Arrays zu verketten oder zu ersetzen, abhängig von der Verwendung.
Mistic

11
Hervorragende Antwort. Die Tests waren sehr didaktisch :-)
Lucio Paiva

5
_.extend is an alias for _.assign, so they are identicalKonflikte mitOnly _.assign will overwrite a value with undefined
Chazt3n

9
Ab Version 4.0 ist _.extend jetzt ein Alias ​​für _.assignIn und nicht für _assign. Die Funktion assignIn fügt hinzu, dass geerbte Eigenschaften behandelt werden.
Mike Hedman

2
Wird null hier genauso behandelt wie undifined?
C_B

75

Ein weiterer zu beachtender Unterschied ist der Umgang mit undefinedWerten:

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

Es mergewerden also keine undefinedWerte zu definierten Werten zusammengeführt.


3
Ist es nur ich oder macht das lodash.extend völlig nutzlos, da es immer einen Klon des 'toMerge'-Objekts zurückgibt?
Jason Rice

6
Wenn mergeIntoEigenschaften vorhanden toMergewären, die diese nicht hätten, würden diese Eigenschaften beibehalten. In diesem Fall wäre es kein Klon.
David Neale

1
@ JasonRice entfernen Sie das leere {} und es wird an Ort und Stelle zusammengeführt lodash.merge (mergeInto, toMerge)
Sidonaldson

20

Es kann auch hilfreich sein, zu überlegen, was sie aus semantischer Sicht tun:

_.zuordnen

   will assign the values of the properties of its second parameter and so on,
   as properties with the same name of the first parameter. (shallow copy & override)

_.verschmelzen

   merge is like assign but does not assign objects but replicates them instead.
  (deep copy)

_.defaults

   provides default values for missing values.
   so will assign only values for keys that do not exist yet in the source.

_.defaultsDeep

   works like _defaults but like merge will not simply copy objects
   and will use recursion instead.

Ich glaube, wenn Sie lernen, diese Methoden aus semantischer Sicht zu betrachten, können Sie besser erraten, wie sich die verschiedenen Szenarien bestehender und nicht existierender Werte verhalten.


3

Wenn Sie eine tiefe Kopie ohne Überschreiben wünschen, während Sie dieselbe objReferenz beibehalten

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

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.