Yashvant's Blog

Yashvant's Blog

Polyfills for Array methods: forEach(), map(), filter(), reduce(),find()

Polyfills for Array methods: forEach(), map(), filter(), reduce(),find()

Yashvant Vala's photo
Yashvant Vala
·Jun 22, 2022·

6 min read

Subscribe to my newsletter and never miss my upcoming articles

Table of contents

  • forEach()
  • Map()
  • Filter()
  • reduce()
  • Find()

It's been a long time since I haven't written any articles but here we go.

In this tutorial, we are going to create our own array method like forEach(), map(), filter(), etc.

Note: if you don't know what polyfills are then please read this article.

If you don't know what are those methods and how to use them then please read my other article here

forEach()

Here is the sample code for how forEach will work.

const person = [
  {
    id:1,
    name:'user1',
    isActive: true,
  },
  {
    id:2,
    name:'user2',
    isActive: true,
  }, 
  {
    id:3,
    name:'user3',
    isActive: true,
  }, 
  {
    id:4,
    name:'user4',
    isActive: true,
  }  
]

person.forEach(data=>{
  data.isActive = false;
})

console.log(person)

Output:

[
  { id: 1, name: 'user1', isActive: false },
  { id: 2, name: 'user2', isActive: false },
  { id: 3, name: 'user3', isActive: false },
  { id: 4, name: 'user4', isActive: false }
]

Here I am manipulating the isActive to false. so how can we create our own method like this, to know that see the below example

const person = [
  {
    id:1,
    name:'user1',
    isActive: true,
  },
  {
    id:2,
    name:'user2',
    isActive: true,
  }, 
  {
    id:3,
    name:'user3',
    isActive: true,
  }, 
  {
    id:4,
    name:'user4',
    isActive: true,
  }  
]
Array.prototype.myForEach = function(callback){
  for(let i=0;i<this.length;i++){
    callback(this[i],i, this);
  }
}

person.myForEach(data=>{
  data.isActive = false;
})

console.log(person)

Output:

[
  { id: 1, name: 'user1', isActive: false },
  { id: 2, name: 'user2', isActive: false },
  { id: 3, name: 'user3', isActive: false },
  { id: 4, name: 'user4', isActive: false }
]

In the above example, I have named the method as myForEach and added it to the prototype of the array so it can be available for any array data structure. once we add the method we can use the array using this keyword because we are calling the method using the (.) operator with the array, which means the context of this will be the object where we have called the method.

And above example will give the same output as forEach().

Map()

const person = [
  {
    id:1,
    name:'user1',
    isActive: true,
  },
  {
    id:2,
    name:'user2',
    isActive: true,
  }, 
  {
    id:3,
    name:'user3',
    isActive: true,
  }, 
  {
    id:4,
    name:'user4',
    isActive: true,
  }  
]

const newPerson = person.map(data=>{
  return {...data, isActive:false};
})

console.log(newPerson)

In the above code, we are making isActive as false and it will return a new array, unlike forEach. So the output would be something like this.

Output:

[
  { id: 1, name: 'user1', isActive: false },
  { id: 2, name: 'user2', isActive: false },
  { id: 3, name: 'user3', isActive: false },
  { id: 4, name: 'user4', isActive: false }
]

below is the polyfill for the map method,

Array.prototype.myMap = function(callback){
  const newArray = [];
  for(let i=0;i<this.length;i++){
    newArray.push(callback(this[i],i, this));
  }
  return newArray;
}

const newPerson = person.myMap(data=>{
  return {...data, isActive:false};
})

console.log(newPerson)

Output:

[
  { id: 1, name: 'user1', isActive: false },
  { id: 2, name: 'user2', isActive: false },
  { id: 3, name: 'user3', isActive: false },
  { id: 4, name: 'user4', isActive: false }
]

It is very similar to forEach, the difference is just we are returning a new array with the result of the callback function. so the output will be the same.

Filter()

See below example where we are filtering the users based on the isActive parameter.

const person = [
  {
    id:1,
    name:'user1',
    isActive: true,
  },
  {
    id:2,
    name:'user2',
    isActive: false,
  }, 
  {
    id:3,
    name:'user3',
    isActive: true,
  }, 
  {
    id:4,
    name:'user4',
    isActive: false,
  }  
]

const newPerson = person.filter(data=>{
  return data.isActive;
})

console.log(newPerson)

Output:

[
  { id: 1, name: 'user1', isActive: true },
  { id: 3, name: 'user3', isActive: true }
]

it is similar to a map but it will only return those items which match the condition in the return statement. so let's write polyfill for that

Array.prototype.myFilter = function(callback){
  const newArray = [];
  for(let i=0;i<this.length;i++){
    if(callback.call(this, this[i],i, this)){
      newArray.push(this[i]);
    }
  }
  return newArray;
}
const person = [
  {
    id:1,
    name:'user1',
    isActive: true,
  },
  {
    id:2,
    name:'user2',
    isActive: false,
  }, 
  {
    id:3,
    name:'user3',
    isActive: true,
  }, 
  {
    id:4,
    name:'user4',
    isActive: false,
  }  
]

const newPerson = person.myFilter(data=>{
  return data.isActive;
})

console.log(newPerson)

Output:

[
  { id: 1, name: 'user1', isActive: true },
  { id: 3, name: 'user3', isActive: true }
]

Here we are calling the callback using call method to provide the context of an array. when if the condition becomes true then we are pushing the array and we are only returning those items which satisfy the condition.

reduce()

const person = [
  {
    id:1,
    name:'user1',
    isActive: true,
    balance: 20,
  },
  {
    id:2,
    name:'user2',
    isActive: false,
    balance: 30,
  }, 
  {
    id:3,
    name:'user3',
    isActive: true,
    balance: 40,
  }, 
  {
    id:4,
    name:'user4',
    isActive: false,
    balance: 50,
  }  
]

const totalBalance = person.reduce((accumulator,data)=>{
  return accumulator+=data.balance;
}, 0)

console.log(totalBalance)

Output:

140

Here I've added one more field called balance and I want the total sum of the balance so we can use the reduce method to make the sum out of it. note that the callback function first argument will be the different and we have provided the initial value as 0.

let's see the polyfill for reduce method in the below example.

Array.prototype.myReduce = function(callback, initialValue){
  let accumulator = initialValue===undefined ? undefined: initialValue;
  for(let i=0;i<this.length;i++){
    if(accumulator!==undefined){
      accumulator = callback.call(undefined, accumulator, this[i], i, this)
    }else{
      accumulator = this[i];
    }
  }
  return accumulator;
}
const person = [
  {
    id:1,
    name:'user1',
    isActive: true,
    balance: 20,
  },
  {
    id:2,
    name:'user2',
    isActive: false,
    balance: 30,
  }, 
  {
    id:3,
    name:'user3',
    isActive: true,
    balance: 40,
  }, 
  {
    id:4,
    name:'user4',
    isActive: false,
    balance: 50,
  }  
]

const totalBalance = person.myReduce((accumulator,data)=>{
  return accumulator+=data.balance;
}, 0)

console.log(totalBalance)

Output

140

here we are passing one more parameter which is the initial value, we are calling the callback using call method and assigning the result to the accumulator so we will get the sum out of it or whatever logic we have written inside the callback function.

Note: don't forget to provide the initial value otherwise as we can see in the polyfill it will assign this[i] means the whole object and we have to extract the value out of it.

Find()

find() is very similar to the filter method but here we are only sending one result.

const foundPerson = person.find(data=>{
  return data.name === 'user1';
})

console.log(foundPerson)

Output:

{ id: 1, name: 'user1', isActive: true, balance: 20 }

As we can see the output that it will only return one record.

Array.prototype.myFind = function(callback, initialValue){
  for(let i=0;i<this.length;i++){
    if(callback.call(accumulator, this[i], i, this)){
      return this[i]
    }
  }
  return accumulator;
}
const person = [
  {
    id:1,
    name:'user1',
    isActive: true,
    balance: 20,
  },
  {
    id:2,
    name:'user2',
    isActive: false,
    balance: 30,
  }, 
  {
    id:3,
    name:'user3',
    isActive: true,
    balance: 40,
  }, 
  {
    id:4,
    name:'user4',
    isActive: false,
    balance: 50,
  }  
]

const foundPerson = person.find(data=>{
  return data.name === 'user1';
})

console.log(foundPerson)

Output

{ id: 1, name: 'user1', isActive: true, balance: 20 }

In the polyfill, we are directly returning the record which matches the condition,

Similarly, there is one more method findIndex which is very same as find, this method will return the index of the array record which match the condition, to achieve that in find polyfill you can write in return statement as return i instead of return this[i] and in else block you can return -1.

So this was it for the polyfill, Hope you get some knowledge from here and if any doubt please write me comment, i would be glad to solve your doubt.

More polyfills are coming, stay tuned and see you in the next article!

signing off!

 
Share this