简体   繁体   中英

Why does underscore.reduce acts differently in these two cases?

I was trying to flatten an object that has two objects in it, so I did the following:

var underscore = require('underscore');
var obj = { a: {x:1}, b: {y:2}};
underscore.reduce(obj, underscore.extend, {});

Unexpectedly, the output that I've got was:

{ 
   '0': 'b',
   x: 1,
   a: { x: 1 },
   b: { y: 2 },
   y: 2 
}

So then I've tried to wrap extend in a function:

underscore.reduce(obj, function(memo, o) {
   return underscore.extend(memo, o);
}, {});

And got the expected result:

{ x: 1, y: 2 }

Why is there any difference? reduce expected as the 2nd argument a function that gets two arguments and returns one, and it gets it in both cases. So what am I missing?

reduce expected as the 2nd argument a function that gets two arguments and returns one...

Not according to the documentation . Underscore passes the iterator four , not two, arguments:

The iterator is passed four arguments: the memo , then the value and index (or key ) of the iteration, and finally a reference to the entire list .

Consequently, you end up calling extend (on the first pass) like this:

underscore.extend({}, {x: 1}, 'a', obj)

and then the second pass

underscore.extend({/*...stuff...*/}, {y: 2}, 'b', obj)

The reason the object has a '0': 'b' attribute is that strings extend into an object containing attributes like '<index>': '<char>' . This is because _.extend runs a for...in... loop on each argument (except the first) and the keys found by doing that to a string are the character indexes (from 0 to str.length - 1 ).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM