Reputation: 68
JavaScript newbie here. Today I learned about reduce
and set out to implement my own array flatten function.
What I had was
var array = [[1, 2], [3, 4, 5], [6]];
var result = array.reduce(Array.prototype.concat, []); // Causes Uncaught TypeError: Array.prototype.concat called on null or undefined
var result = array.reduce(Array.prototype.concat.call, []); // Causes Uncaught TypeError: undefined is not a function
While answers in Merge/flatten an array of arrays in JavaScript? are elegant and idiomatic, I'd really appreciate an illustration on how my attempts failed.
Upvotes: 4
Views: 1475
Reputation: 225095
You have the right idea with Array.prototype.concat.call
. With Array.prototype.concat
, the calls are going to look like this:
var concat = Array.prototype.concat;
concat(concat(concat([],
[1, 2]),
[3, 4, 5]),
[6])
which doesn’t work because Array.prototype.concat
concatenates its arguments to its this
; calling it as concat()
gives it a this
of undefined
. How about with call
?
var call = Array.prototype.concat.call;
call(call(call([],
[1, 2]),
[3, 4, 5]),
[6])
This runs into the same problem, but with Function.prototype.call
(Array.prototype.concat
is a function like any other, and inherits its call
method from Function.prototype
). call
tries to call its this
, but calling it as call()
gives it a this
of undefined
.
You could pass Function.prototype.call.bind(Array.prototype.concat)
… if reduce
didn’t call its function with more arguments than just the accumulator and the current item. But it does, passing the index of the current item and context array as well, and ruining any chance of making this work by passing only Array.prototype.concat
wrapped with some builtins.
Upvotes: 2
Reputation: 2666
This is so because Array.prototype.concat
requires a function prototype such that it is an array or list of values to be concatenated to the main array.
However, the callback to Array.prototype.reduce
requires an accumulator
, currentValue
, currentIndex
and array
as parameters.
The parameters (as well as what they're supposed to do) don't match and hence, you get unexpected results or errors.
Upvotes: 0
Reputation: 1
your code is equivalent of
result = array.reduce(fn, []);
function fn(a, b, index, array) { // this is the arguments reduce sends to the callback
return Array.prototype.concat.call(null, a, b, index, array);
}
can you spot the problem?
Upvotes: 4