Lodash – différence entre .extend () / .assign () et .merge ()

Dans la bibliothèque Lodash , quelqu'un peut-il fournir une meilleure explication de fusion et d' extension / affectation .

C'est une question simple, mais la réponse m'échappe néanmoins.

Voici comment l' extend / assign fonctionne: pour chaque propriété en source, copiez sa valeur telle qu'elle est destinée à la destination. Si les valeurs de propriété elles-mêmes sont des objets, il n'y a pas de parcours récursif de leurs propriétés. L'objet entier serait retiré de la source et configuré dans la destination.

Voici comment fonctionne la merge : pour chaque propriété en provenance, vérifiez si cette propriété est l'objet lui-même. Si c'est le cas, passez de manière récursive et essayez de mapper les propriétés de l'objet enfant de la source à la destination. Donc, essentiellement, nous fusionnons la hiérarchie des objets de source en destination. Bien que pour extend / assign , il s'agit d'une simple copie de niveau de propriétés de source en destination.

Voici JSBin simple qui rendrait ce cristal clair: http://jsbin.com/uXaqIMa/2/edit?js,console

Voici une version plus élaborée qui comprend également le tableau dans l'exemple: http://jsbin.com/uXaqIMa/1/edit?js,console

Lodash version 3.10.1

Méthodes comparées

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

Similitudes

  • Aucun d'entre eux ne travaille sur des tableaux comme vous pouvez l'attendre
  • _.extend est un alias pour _.assign , donc ils sont identiques
  • Tous semblent modifier l'objet cible (premier argument)
  • Tous manipulent null the same

Différences

  • _.defaults et _.defaultsDeep aux arguments en ordre inverse par rapport aux autres (bien que le premier argument reste l'objet cible)
  • _.merge et _.defaultsDeep fusionneront des objets enfants et les autres écraseront au niveau racine
  • Seul _.assign et _.extend remplissent une valeur avec undefined

Tests

Ils traitent tous les membres de la racine de manière similaire.

 _.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 poignées undefined mais les autres l' _.assign

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

Ils mangent tous null le même

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

Mais seulement _.merge et _.defaultsDeep fusionneront des objets enfants

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

Et aucun d'eux ne fusionnera les tableaux, il semble

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

Tous modifient l'objet cible

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

Aucun ne fonctionne vraiment comme prévu sur les tableaux

Remarque: Comme l'a souligné @Mistic, Lodash traite les tableaux comme objets où les clés sont l'index dans le tableau.

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

Une autre différence à mettre en évidence est la gestion de valeurs undefined :

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

Donc, la merge ne fusionnera undefined valeurs undefined valeurs définies.

Il pourrait également être utile de considérer ce qu'ils font d'un point de vue sémantique:

_.attribuer

  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) 

_.fusionner

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

__Refaults

  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. 

Je crois qu'apprendre à penser à ces méthodes du point de vue sémantique vous permettrait de mieux "deviner" quel serait le comportement de tous les différents scénarios de valeurs existantes et non existantes.