Straight forward questions like what is an Array reduce are hardly asked in Javascript interviews. But you might be asked problems where you need to apply Array reduce. It's important to know where exactly you need an Array reduce in Javascript. You'll be judged on the how you apply it.

Let's start with a recap of the Array reduce method in Javascript. Feel free to skip this section, if you already know how it works.

What is an Array reduce method in Javascript?

reduce is a method available to all arrays in Javascript. As the name suggests, it is used to reduce the array to a single value. It does not mutate the array. It loops over the array and outputs a single reduced value. Every iteration takes the output from the previous iteration and performs the supplied operation using that value and the current value. We can pass a seed value to the first iteration. If we don't the element at index 0 is taken as the seed value and looping starts from index 1.

arr.reduce(callback, accumulator);

// callback - The function that defines what you want to do with the currentValue & the accumulated value

// accumulator - The seed value. If not provided, value of first array element is taken as the seed value

The callback function receives 4 parameters:

// callback
(accumulator, currentValue, currentIndex, arr) => {}
  • accumulator: Accumulated Value. To start with, it is equal to the value of provided accumulator, otherwise the value at first index of the array.
  • currentValue: Value at the current index
  • currentIndex: Current index
  • arr: Array on which reduce was called
const numbers = [1, 2, 3, 4];
const sum = numbers.reduce((total, value) => total +  value);
console.log(sum); // -> prints 10
const numbers = [2, 3, 4, 8];
const product = numbers.reduce((total, value) => total *  value, 2);
console.log(product); // -> prints 384

Implementing Reduce

Next we see a simple implementation of array reduce in javascript. Lets start with the test cases:

// With empty Array and no initial value specified
// Expect a type error
[].reduce((total, value) => total * value)

// With empty Array but has initial value 
// Returns initial value
[].reduce((total, value) => total * value, 2)

// Happy case
// Returns 384
[2, 3, 4, 8].reduce((total, value) => total *  value, 2)

// Callback not provided
// Expect a type error
[2, 3, 4, 8].reduce()
// Check if reduce does not already exist so that you don't override it

if (!Array.prototype.myReduce) {

  // Add a reduce method to prototype so that it is available to all arrays
    
  Array.prototype.myReduce = function (callback, acc) {

    // Check if callback is a function
      
    if(typeof callback !== 'function') {
      throw new TypeError('Callback is not a function')
    }

    // Check if reduce called on empty array without providing initial value
      
    if (this.length === 0 && typeof acc === 'undefined') {
      throw new TypeError("Reduce of empty array with no initial value");
    }

    var accumulator = typeof acc === 'undefined' ? this[0] : acc;
    var i = acc ? 0 : 1;
    for (; i < this.length; i++) {
      accumulator = callback(accumulator, this[i], i, this)
    }
    return accumulator;
  }
}

We need a couple of checks here:

1) If the callback is supplied

2) If reduce was not called on an empty array with no initial value provided

In both the above cases, it should throw a TypeError. A TypeError basically signifies that the supplied operand or argument was not of expected type.

Next we check if an initial value is provided or not. If it is we take it as the seed value and start looping from index 0, otherwise we consider first array element as the seed value and start the loop from array index 1.

With each iteration, we make a call to the callback with the appropriate params while updating the accumulator.

Finally return back the accumulator. That's it.

This implementation should be good enough for most of the junior - mid-senior javascript interviews. 95% interviewers would be happy with this implementation.

For senior roles that involve writing core libraries, the implementation might need a few additional things:

1) How do you use this implementation for cases with Array.prototype.myReduce.call(...)

2) Can you make this implementation better for sparse arrays? We are looping over every array element here. Doing that for sparse arrays is not performant. How do we solve that?