Lodash - difference between .extend() / .assign() and .merge()


In the Lodash library, can someone provide a better explanation of merge and extend / assign.

Its a simple question but the answer evades me nonetheless.

3/21/2014 2:21:37 PM

Accepted Answer

Here's how extend/assign works: For each property in source, copy its value as-is to destination. if property values themselves are objects, there is no recursive traversal of their properties. Entire object would be taken from source and set in to destination.

Here's how merge works: For each property in source, check if that property is object itself. If it is then go down recursively and try to map child object properties from source to destination. So essentially we merge object hierarchy from source to destination. While for extend/assign, it's simple one level copy of properties from source to destination.

Here's simple JSBin that would make this crystal clear:,console

Here's more elaborate version that includes array in the example as well:,console

12/7/2015 1:38:39 PM

Another difference to pay attention to is handling of undefined values:

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

So merge will not merge undefined values into defined values.


It might be also helpful to consider what they do from a semantic point of view:


   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 is like assign but does not assign objects but replicates them instead.
  (deep copy)


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


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

I believe that learning to think of those methods from the semantic point of view would let you better "guess" what would be the behavior for all the different scenarios of existing and non existing values.


If you want a deep copy without override while retaining the same obj reference

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