Writing polyfill of reduce method present on Array in JavaScript

Writing polyfill of reduce method present on Array in JavaScript

ยท

4 min read

Introduction

JavaScript is a versatile programming language that provides developers with a rich set of built-in methods to manipulate arrays. One such method is reduce(), which allows you to perform powerful operations on arrays by reducing them to a single value. In this article, we will explore the concept of reduce(), its benefits, and learn how to write our own polyfill for the reduce() method.

Understanding Array.reduce():

The reduce() method is used to iterate over an array and accumulate a single value by applying a provided function to each element.

It takes two parameters: a callback function and an optional initial value. The callback function receives 4 arguments: an accumulator (the value accumulated so far), the current element being processed, the current index from the array & the entire array.

The callback function can perform any operation on the elements and modify the accumulator as needed. The reduce() method returns the final accumulated value.

Benefits of using Array.reduce():

The reduce() method offers several advantages that make it a powerful tool for array manipulation:

  1. Summarizing Data: reduce() allows you to calculate a single value based on the elements of an array. For example, you can easily find the sum, product, or average of an array of numbers using the reduce() method.

  2. Transforming Data: By providing a transformation function, you can use reduce() to convert an array into a different data structure or format. This is particularly useful when dealing with complex data manipulations or aggregations.

  3. Filtering Data: reduce() can be used to filter out specific elements from an array based on a condition. You can accumulate only the desired elements by applying filtering logic within the callback function.

  4. Performing Complex Operations: With reduce(), you can perform more complex operations such as finding the maximum or minimum value, concatenating strings, or even building entirely new arrays.

Now, that you know what is reduce method & its usage. Let's get started with writing the polyfill for reduce method.

Polyfill for Array.prototype.reduce

Let me first show you the entire code, then we will go step by step understanding bits and pieces of it.

Array.prototype.myReduce = function (callbackFn, initialValue) {
  if (this.length === 0 && initialValue === undefined) {
    throw new TypeError("cant perform reduce of an empty array with no initial value");
  }

  if (initialValue === undefined) {
    initialValue = this[0];
  }

  let acc = initialValue;

  let i = 0;
  if (arguments.length < 2) {
    // meaning: if there is no initial value, the 1st index of array is taken in acc, so we will be iterating from 2nd.
    i = 1;
  }

  // callback function takes, (acc, curr, index, array)
  for (; i < this.length; i++) {
    acc = callbackFn(acc, this[i], i, this);
  }

  return acc;
};

We are adding the function to Array.prototype so that we can directly use it on arrays with the dot notation and with the name myReduce.

Looking for Edge cases:

In the reduce implementation, we notice that, if we provide an empty array length & with no initial value, we get a TypeError with the message as presented below

Hence, we are adding our first check

if (this.length === 0 && initialValue === undefined) {
    throw new TypeError("cant perform reduce of an empty array with no initial value");
  }

Next, we are checking if the user has provided the initialValue or not. Based on the definition of reduce from MDN we know that if there is not initialValue defined, then we pass on the 1st index of the array.

And that is why we add this check

if (initialValue === undefined) {
    initialValue = this[0];
}

Now, from the definition, we know that the accumulator is the total value so far & in the 1st iteration, it will be equivalent to the 1st index of the array element.

We also perform a check,

let i = 0;
if (arguments.length < 2) {
  i = 1;
}

This is to know that if we had got an initialValue at the start, if not, then we are assigning i=1 which means the iteration will start from 1 simply because now acc has the 1st index of the array.
If not, the iteration will start from 0 with the initialValue provided by the user.

Next, we have a simple for loop which iterates over the array and calls the callback function & thus returning the acc aka accumulator.

for (; i < this.length; i++) {
  acc = callbackFn(acc, this[i], i, this);
}
return acc;

Combine all of these steps, and you get ๐Ÿ‘‡

Array.prototype.myReduce = function (callbackFn, initialValue) {
  if (this.length === 0 && initialValue === undefined) {
    throw new TypeError("cant perform reduce of an empty array with no initial value");
  }

  if (initialValue === undefined) {
    initialValue = this[0];
  }

  let acc = initialValue;

  let i = 0;
  if (arguments.length < 2) {
    i = 1;
  }

  for (; i < this.length; i++) {
    acc = callbackFn(acc, this[i], i, this);
  }

  return acc;
};

That's it, folks.
I hope this was useful and made the reduce method more clear now.

I have also written other polyfills & I am maintaining this repository on github, check it out & give it a star.

Thank you!