Array.prototype.reduce and the optional initial value

| 2 min read

Today I learned about the subtlety of the optional initialValue parameter for the Array prototype's reduce method in JavaScript.

This is almost too trivial to write about, but I was surprised to discover the behaviour, so perhaps others will be too.

I've recently been exploring functional programming on our Hands-on SAP Dev show and had highlighted reduce both in native Node.js JavaScript and in the Ramda flavour. There are generally three parameters to a reduce call:

  • the iterator function ("callbackFn")
  • an initial value for the accumulator ("initialValue")
  • the list of values upon which to iterate ("list")

The way that the standard JavaScript reduce works, being a method available on the Array prototype, is that the "list" is provided not as an argument explicitly, but as the instance of the Array on which the reduce method is being called; then quite often the "callbackFn" is passed as the first argument, and that's it - no "initialValue":

list.reduce(callbackFn)

The Ramda flavour of reduce is a regular function that expects three parameters, and (even when employing partial application) it's not really possible to omit the "initialValue" here:

R.reduce(callbackFn, initialValue, list)

With Array.prototype.reduce, the "initialValue" is optional. And all this time I hadn't thought much about what that implied; I think I might have (mistakenly) assumed it will (waves hands in air) choose the appropriate starting value - but investing any amount of thinking effort here reveals that expectation to be nonsensical.

The mechanics of reduce are such that each item of the "list" is passed, in turn, to the "callbackFn", along with an accumulator, which starts out being set to the "initialValue". This can be illustrated with the following example:

const nums = [1,2,3]
const myadd = (x, y) => {
console.log(`${x} + ${y}`)
return x + y
}

Calling nums.reduce(myadd, 0), i.e. supplying an "initialValue", we see this:

0 + 1
1 + 2
3 + 3

6

So far so good.

But calling nums.reduce(myadd) without an "initialValue", we see this:

1 + 2
3 + 3

6

One iteration fewer.

In other words, and as the MDN documentation states, relating to the accumulator and currentValue parameters of the callbackFn:

If initialValue is not specified, accumulator is initialized to the first value in the array, and callbackFn starts executing with the second value in the array as currentValue.

(emphasis mine). This makes total sense, and is the most practical approach if initialValue is to be optional.

Of course, it goes without saying that this behaviour is only related to the optional nature for initialValue in Array.prototype.reduce; Ramda's reduce cannot exhibit this behaviour as the initialValue parameter is not optional, and we can see that:

reduce(myadd, 0, nums)

emits this:

0 + 1
1 + 2
3 + 3

6

That's it! Thanks again to the authors of the excellent MDN documentation.