I am transforming this array of objects:
[
{
first: {
blah: 1,
baz: 2
}
},
{
second: {
foo: 1,
bar: 2
}
}
]
To this simpler, flat object:
{
first: {
blah: 1,
baz: 2
},
second: {
foo: 1,
bar: 2
}
}
The two simplest ways I found to do this using Underscore/LoDash are:
// Using reduce and extend
_.reduce(myArray, _.extend)
// Using assign and apply
_.assign.apply(_, myArray);
The complete code is documented in a JSBin: http://jsbin.com/kovuhu/1/edit?js,console
I've read a lot of documentation on apply/bind/call/assign/reduce/extend… But I just can't get my head around what is actually happening behind the curtains.
Can someone help me understand the secret of the magic tricks both of these one-liners perform?
To understand this, let's make a simple version of assign (alias extend). We will only accept one argument, which we will call source, and we will add it to our result.
function assign(result, source) {
var keys = Object.keys(source),
length = keys.length;
for (var i=0 ; i < length; i ++) {
var key = keys[i];
result[key] = source[key];
}
return result;
}
Now let's break the input into pieces:
var a = {
first: {
blah: 1,
baz: 2
}
}
var b = {
second: {
foo: 1,
bar: 2
}
}
var input = [a, b];
Now we can call reduce:
_.reduce(input, assign);
reduce will call assign twice:
assign(result, a);
// assigns the (key, value) pair ("first", {blah: 1, baz: 2}) to result
assign(result, b);
// assigns the (key, value) pair ("second", {foo: 1, bar: 2}) to result
Talk is cheap, show me the code: http://jsbin.com/hexiza/3/edit?js,console
You can see how assign is implemented using createAssigner() and baseAssign() in the Lo-Dash source code.
reduce
takes all values in an array/properties in an object, and aggregates them. In this case extend
is passed to reduce
, meaning you're passing a function(a,b)
for extending value a
(carried over with each step) with all the properties of object b
(each value in your array, one at a time). In your one liner, underscore's reduce
walks over your array, starting with an object {}, and simply dumps all the array element properties into that object as it walks along your input array. In plain JS it would be something like:
var thing = {};
var deeparray = [{...}, {...}, {...}];
deeparray.forEach(function(v) {
Object.keys(v).forEach(function(k) {
thing[k] = v[k];
}
});
return thing;
assign
(not found in underscore) does the same thing, taking an array of objects and squashing them all together. That's literally the only thing it does. The call _assign.apply(_, myArray)
is the same as _ calling this.assign(myArray)
- apply
is a base JavaScript function for calling a function while "manually overriding" what the keyword this
means inside that function. _.assign.apply(_,myArray)
is the same as calling _.assing(myArray)
except with the added guarantee that this
will be lodash, and not some random function scoped context.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With