Combining Settings Objects with Lodash: _.assign or _.merge?
When you're developing a JavaScript component which lets the user provide an object holding some options, you usually need to merge its values with your component's defaults. Settings for which the user didn't provide a value should fall back to a reasonable default.
Suppose we have the following default and user settings:
// Defined within your component
var defaultSettings = {
strictMode: true,
formatting: {
finalNewline: true,
quotes: "double",
},
};
// Provided by the developer using your component
var userSettings = {
formatting: {
quotes: "single",
},
};
Note that no value for the strictMode
property was specified by the user. That's perfectly fine, we're just going to use the default value of true
. The same goes for the finalNewline
property, we're falling back to true
as well. Only the quotes
value changed from its default value of "double"
to "single"
.
In the end, we'd like the merged settings to look like this:
var settings = {
strictMode: true,
formatting: {
finalNewline: true,
quotes: "single",
},
};
The lodash library contains two similar functions, _.assign
and _.merge
, that assign property values of some source object(s) to a target object, effectively merging their properties. Let's take a look at their differences.
#Merging Properties Using _.assign
The _.assign
function (also called _.extend
) accepts as its first parameter a target object to which all properties of the following parameters will be assigned. Values defined by later parameters will overwrite sooner values.
A common pattern is to provide {}
, an empty object literal, as the target into which all settings are merged. The default values come first, followed by user-provided settings which overwrite already defined properties.
That sounds perfect for merging settings with default fallback values, does't it? Well, not entirely, as this example shows:
var assignedSettings = _.assign({}, defaultSettings, userSettings);
// {
// strictMode: true,
// formatting: {
// quotes: "single"
// }
// }
As you can see, the formatting
property of the user's settings was assigned as a whole, as the _.assign.
name already suggests. The true
value of finalNewline
, another property of the formatting
object, is now lost.
Let's compare this with the behavior of the _.merge
function.
#Merging Properties Using _.merge
The _.merge
function has the same signature as _.assign
, but behaves a little differently. Instead of assigning values as a whole, it recursively merges properties that don't hold the value undefined
into the target object.
Let's combine the user settings with the default values once more:
var mergedSettings = _.merge({}, defaultSettings, userSettings);
// {
// strictMode: true,
// formatting: {
// finalNewline: true,
// quotes: "single"
// }
// }
Much better! Now, the formatting
object hasn't been replaced by the partial user definition, but has had its default values merged with the user settings.
So, if you intend to perform a deep merge of user-provided settings with your own default values, use _.merge
rather than _.assign
.