A simple recursive function does the trick
As @torazaburo notes in a comment, if you can use ES6, the destructuring assignment clears the implementation even more
// ES6 function reduce([x, ...xs], f, acc) { if (x === undefined) return acc else return reduce(xs, f, f(acc, x)) }
Or it becomes super sweet sweet with arrow functions
// ES6, same as above but using arrow function and ternary expression const reduce = ([x, ...xs], f, acc)=> x === undefined ? acc : reduce(xs, f, f(acc, x))
The Underscore implementation does provide some other convenience, although I assume they are here to maintain compatibility with the native Array.prototype.reduce . I personally will not implement this, but it is not.
- The underscore passes the iterator and arr reference to the callback function.
- Underscore lets you change the context for a callback function
Here's a revised implementation that supports these other features.
// our reduce version 2.0 function reduce(collection, iterator, memo, context) { function loop(memo, i) { if (collection.length === i) return memo else return loop(iterator.call(context, memo, collection[i], i, collection), i + 1) } return loop(memo, 0) }
You can use it in the same way as above, only now it provides additional information for a callback
Note
I deliberately decided not to implement the Underscore pruning behavior, which allows pruning without an initial value. Supporting this behavior leads to unsafe code and should never have turned into Underscore.