Lodash-różnica między.extend() /.assign () i.merge()

W Lodash Czy ktoś może podać lepsze wyjaśnienie merge i extend / assign.

To proste pytanie, ale odpowiedź mi umyka.

Author: Droogans, 2013-11-14

4 answers

Oto jak extend/assign działa: dla każdej właściwości w source skopiuj jej wartość AS-is do miejsca docelowego. jeśli same wartości właściwości są obiektami, nie ma rekurencyjnego przejścia ich właściwości. Cały obiekt zostanie pobrany ze źródła i ustawiony do miejsca docelowego.

Oto jak działa merge: dla każdej właściwości w source sprawdź, czy ta właściwość jest obiektem. Jeśli tak jest, przejdź rekurencyjnie w dół i spróbuj odwzorować właściwości obiektu potomnego ze źródła do miejsca docelowego. Więc zasadniczo łączymy hierarchia obiektów od źródła do miejsca docelowego. While for extend/assign, jest to prosta jednopoziomowa Kopia właściwości od źródła do miejsca docelowego.

Oto prosty JSBin, który uczyniłby to krystalicznie czystym: http://jsbin.com/uXaqIMa/2/edit?js, console

Oto bardziej rozbudowana wersja, która zawiera również tablicę w przykładzie: http://jsbin.com/uXaqIMa/1/edit?js, console

 504
Author: ShitalShah,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-07 13:38:39

Wersja Lodash 3.10.1

Metody porównywane

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

Podobieństwa

  • żaden z nich nie działa na tablicach, jak można się spodziewać
  • _.extend jest aliasem dla _.assign, więc są identyczne
  • Wszystkie z nich wydają się modyfikować obiekt docelowy (pierwszy argument)
  • wszystkie obsługują null to samo

Różnice

  • _.defaults i _.defaultsDeep przetwarza argumenty w odwrotnej kolejności w porównaniu do innych (choć pierwszy argument jest nadal obiektem docelowym)
  • _.merge i _.defaultsDeep Scali obiekty potomne, a pozostałe nadpiszą na poziomie głównym
  • tylko _.assign i _.extend nadpiszą wartość undefined

Testy

Oni wszyscy obsługują członków u źródła w podobny sposób.

_.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 uchwyty undefined ale inni o tym zapomną

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

Wszystkie obsługują null to samo

_.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 }

Ale tylko _.merge i _.defaultsDeep będą scalać obiekty potomne

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

I żadna z nich nie połączy tablic wygląda na to, że

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

Wszystkie modyfikują obiekt docelowy

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

Żaden naprawdę nie działa zgodnie z oczekiwaniami na tablicach

Uwaga: Jak zauważył @Mistic, Lodash traktuje tablice jako obiekty, w których klucze są indeksem do tablicy.

_.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"  ]
 422
Author: Nate,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-07 14:55:00

Kolejną różnicą, na którą należy zwrócić uwagę, jest obsługa undefined wartości:

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

Więc merge nie połączy undefined wartości do zdefiniowanych wartości.

 72
Author: samz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-20 17:24:57

Pomocne może być również rozważenie tego, co robią z semantycznego punktu widzenia:

_.assign

   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)

_.merge

   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.

Wierzę, że nauka myślenia o tych metodach z semantycznego punktu widzenia pozwoli Ci lepiej "odgadnąć", jakie byłoby zachowanie dla wszystkich różnych scenariuszy istniejących i nieistniejących wartości.

 17
Author: epeleg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-31 07:06:45