ยป npm install lodash.assign
ยป npm install @types/lodash.assign
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: http://jsbin.com/uXaqIMa/2/edit?js,console
Here's more elaborate version that includes array in the example as well: http://jsbin.com/uXaqIMa/1/edit?js,console
Lodash version 3.10.1
Methods compared
_.merge(object, [sources], [customizer], [thisArg])_.assign(object, [sources], [customizer], [thisArg])_.extend(object, [sources], [customizer], [thisArg])_.defaults(object, [sources])_.defaultsDeep(object, [sources])
Similarities
- None of them work on arrays as you might expect
_.extendis an alias for_.assign, so they are identical- All of them seem to modify the target object (first argument)
- All of them handle
nullthe same
Differences
_.defaultsand_.defaultsDeepprocesses the arguments in reverse order compared to the others (though the first argument is still the target object)_.mergeand_.defaultsDeepwill merge child objects and the others will overwrite at the root level- Only
_.assignand_.extendwill overwrite a value withundefined
Tests
They all handle members at the root in similar ways.
_.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 handles undefined but the others will skip it
_.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" }
They all handle null the same
_.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 }
But only _.merge and _.defaultsDeep will merge child objects
_.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" }}
And none of them will merge arrays it seems
_.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" ] }
All modify the target object
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" }
None really work as expected on arrays
Note: As @Mistic pointed out, Lodash treats arrays as objects where the keys are the index into the array.
_.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" ]
Depends on the browser. Per the lodash docs:
Made _.assign use built-in Object.assign when available.
You can go here for browser support:
Basically, IE doesn't have support so lodash's code is used in that case
MDN Docs on Object.assign
Adding to the other comments, according to this small benchmark, it seems that Object.assign is a bit faster then Lodash.assign.
The most common way of doing this seems to use an empty object and assign onto that, like:
var result = _.assign({}, l, m, n, o, p);
This is not technically immutable but will produce a "new" object that did not exist before the function was called.
Bear in mind that even a very clever implementation of clone would have to do this same thing. It's trivial to create the new object manually, so most libraries don't worry about a helper for this case. The next closest thing would be _.create, which has more to do with assigning the correct prototype.
I like defaults() for cases like this.
var user = { user: 'barney', age: 36 };
_.defaults({ age: 40 }, user);
// โ { user: 'barney', age: 40 }
user;
// โ { user: 'barney', age: 36 }
The first argument is the destination, and user isn't mutated. I like using defaults() when I need to override properties, as is the case here with age, but don't want to actually change anything in the original. Because defaults() will only add properties that resolve to undefined. The age property exists in the object literal, so it's value is kept.
The assign() approach works just as well - defaults() is just a different way to think about it.