Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript reduce gotcha - skips first iteration?

Why does javascript's implementation of reduce skip execution for the first iteration?

[1,2,3].reduce((acc, val) => {
    console.log('acc',acc);
    console.log('val',val)
    return acc + val;
});
// acc 1
// val 2
// acc 3
// val 3
// 6

I notice that the first statement execution never runs (in this case, I would have expected there to be 6 console logs, 2 for each element). This was very unexpected behavior when I was trying to execute a function with a side effect within each iteration with reduce.

In other languages that I've used, every iteration of the list passed executes. Are there examples otherwise?

Why does this happen and why is the implementation of javascript's native Array reduce like this?

========================= EDIT 1/Solution ========================
To make sure it goes through the first iteration, give it an initial value (the 2nd argument here/ 0 in this case)

[1,2,3].reduce((acc, val) => { console.log('acc',acc); console.log('val',val) return acc + val; }, 0);

like image 800
JaTo Avatar asked Sep 09 '18 14:09

JaTo


People also ask

What is reduce () in JavaScript?

The reduce() method executes a user-supplied "reducer" callback function on each element of the array, in order, passing in the return value from the calculation on the preceding element. The final result of running the reducer across all elements of the array is a single value.

How do you use reduce on array of objects in JavaScript?

The reduce() method executes the function for each value of the array (non-empty array) from left to right. The reduce() method has the following syntax: let arr = [];arr. reduce(callback(acc, curVal, index, src), initVal);

What is accumulator in reduce JavaScript?

accumulator is the value returned from the previous iteration. It will be initialValue for the first iteration.

How implement reduce in JavaScript?

Whenever you feel you are ready, go through the next steps on how to implement your custom reduce() : Initialize accumulator variable with 0 or initalValue argument from the reduce() . Loop through the array elements. Call the reducer function with the accumulator and current element as the arguments.


1 Answers

That is because of the fact that on every iteration, the first value is treated as a return value (or the accumulator).

Straight from here, you can see

The accumulator accumulates the callback's return values; it is the accumulated value previously returned in the last invocation of the callback, or initialValue, if supplied (see below).


If we look at the source code here, we can see how it's implemented:

Array.prototype.myReduce = function(callback, initialVal) {
    var accumulator = (initialVal === undefined) ? undefined : initialVal;
    for (var i = 0; i < this.length; i++) {
        if (accumulator !== undefined)
            accumulator = callback.call(undefined, accumulator, this[i], i, this);
        else
            accumulator = this[i];
    }
    return accumulator;
};

In the else structure, we can see that if the value is undefined, we set it to the i-th subindex in the array; which, for the first iteration, is the first one. After that, it becomes the callback (return) value of the iterations which follow.

If you want, you can backtrack and check the output.

like image 110
weirdpanda Avatar answered Oct 16 '22 13:10

weirdpanda