DEV Community

Cover image for Polyfills for Array methods: forEach(), map(), filter(), reduce(),find()
yashvant vala
yashvant vala

Posted on

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

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

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

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 }
]

Enter fullscreen mode Exit fullscreen mode

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 }
]

Enter fullscreen mode Exit fullscreen mode

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)

Enter fullscreen mode Exit fullscreen mode

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 }
]

Enter fullscreen mode Exit fullscreen mode

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 }
]

Enter fullscreen mode Exit fullscreen mode

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 }
]

Enter fullscreen mode Exit fullscreen mode

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 }
]

Enter fullscreen mode Exit fullscreen mode

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.

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

Enter fullscreen mode Exit fullscreen mode

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

Enter fullscreen mode Exit fullscreen mode

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 }

Enter fullscreen mode Exit fullscreen mode

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 }

Enter fullscreen mode Exit fullscreen mode

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!

Top comments (0)