With the following
var a = {
a: 0,
b: [],
c: "",
d: { "x": "y", "g": "f" },
e: {},
f: function () { return undefined; }(),
g: false
};
var b = {
a: { "a": "b" },
b: { "c": "d" },
c: { "e": "f" },
d: { "g": "h" },
e: { "i": "j" },
f: {},
g: { "m": "n" },
};
If you look at the datatypes, I have the falsy or empty version of several (or a close approximation): Number, Array,String,Object,undefined, Boolean.
Using the above with the following:
var assinged = _.assign({}, a, b);
var merged = _.merge({}, a, b);
var extended = _.extend({}, a, b);
I get:
assigned:
{
"a": {"a": "b"},
"b": {"c": "d"},
"c": {"e": "f"},
"d": {"g": "h"},
"e": {"i": "j"},
"g": {"m": "n"}
}
merged:
{
"a":{"a":"b"},
"b":[],
"c":{"e":"f"},
"d":{"x":"y","g":"h"},
"e":{"i":"j"},
"g":{"m":"n"}
}
extended:
{
"a": {"a": "b"},
"b": {"c": "d"},
"c": {"e": "f"},
"d": {"g": "h"},
"e": {"i": "j"},
"g": {"m": "n"}
}
SO, assign and extend are equivalent for this example. Merge does the closest to what I want - You look at the key d
, you can see that my existing key is preserved, and the object is extended. However, looking at the b
key, you can see that the empty array is overwriting the object with Merge.
Two questions:
Is there a simple command in lodash that will achieve what I want (a true, complete deep merge, where all properties in the first object are overwritten or extended with values from the second object)?
What choice is _.merge
making here, that is causing this to happen?
However, looking at the
b
key, you can see that the empty array is overwriting the object with Merge
Not overwriting, no.
When you run _.merge({}, a, b).b
you get an empty array with its c
property set to "d"
. It's treating the array like an object, and effectively doing this:
var b = [];
b.c = "d";
// inspect what b is now
console.log(b.length); //=> 0
console.log(b.c); //=> "d"
In javascript an array is, effectively, an object that uses integers keys for many values:
var a = [1,2,3];
a.b = "c";
console.log(Object.keys(a)); //=> ["0", "1", "2", "b"]
You can create arbitrary properties on arrays and even functions in javascript, since they behave just like standard objects do.
So, yeah, it's merging the properties of object b
into object a
recursively exactly as it should.
You may want a more custom merging behavior that you write yourself. This question may help with that effort: