Creating Custom Higher Order Functions
And Why Functions are first class citizens in Javascript
Hi There,
In my previous Map function in Javascript blog post I mentioned, I will make a blog post about how to define our custom map function. Today we are going to do more :) Creating custom map/forEach/filter/reduce higher order functions
(HOC from now on) is a great way to understand/solidify how things work under the hood.
Let us see the code. Comments are added for clarification purposes.
- Custom Map Function
//Guard clause to avoid collision with 3 party software or ESNext versions
if(!Array.prototype.customMap){
Array.prototype.customMap = function(callback){
const result = [];
for(let i = 0 ; i< this.length ; i++){
//Passing array current element,index and original array
//itself in every callback
const itemResult = callback.call(null,this[i],i,this);
result.push(itemResult);
}
return result;
}
}
const numbers = [1,2,3,4,5];
const mappedNumbers = numbers.customMap((num,idx,arr) => {
console.log(`Num= ${num}, Index = ${idx}`);
console.log("Original Array: ",arr);
return num * (idx + 1);
})
console.log("Mapped Numbers:",mappedNumbers);
/* ->
Num= 1, Index = 0
Original Array: (5) [1, 2, 3, 4, 5]
Num= 2, Index = 1
Original Array: (5) [1, 2, 3, 4, 5]
Num= 3, Index = 2
Original Array: (5) [1, 2, 3, 4, 5]
Num= 4, Index = 3
Original Array: (5) [1, 2, 3, 4, 5]
Num= 5, Index = 4
Original Array: (5) [1, 2, 3, 4, 5]
Mapped Numbers: (5) [1, 4, 9, 16, 25]
*/
- Custom ForEach Function
Since there is no need to return a value from forEach
we just call our callback with current item,
index and original array respectively .
if(!Array.prototype.customForEach){
Array.prototype.customForEach = function(callback){
for(let i = 0 ; i< this.length ; i++){
callback.call(null,this[i],i,this)
}
}
}
const numbers = [1,2,3,4,5];
numbers.customForEach(num => console.log(num ** 2)); // -> 1,4,9,16,25
- Custom Filter Function
if(!Array.prototype.customFilter){
Array.prototype.customFilter = function(callback){
const result = [];
for(let i = 0 ; i< this.length ; i++){
//If current item satisfies the criteria(callback result)
// add it to the result array
const itemShouldAdd = callback.call(null,this[i],i,this);
if(itemShouldAdd){
result.push(this[i]);
}
}
return result;
}
}
const numbers = [1,2,3,4,5];
const evenNumbers = numbers.customFilter(num => num % 2 === 0);
console.log(evenNumbers); // -> [2,4]
- Custom Reduce Function
if(!Array.prototype.customReduce){
Array.prototype.customReduce = function(callback,initialValue = undefined){
//if initial value provided for our reduce function
//take it as accumulator initial value(startIndex = 0), otherwise
//assign array first value to accumulator value(startIndex = 1)
let accumulatorValue = initialValue == undefined ? this[0] : initialValue;
const startIndex = initialValue == undefined ? 1 : 0;
for(let i = startIndex ; i< this.length ; i++){
accumulatorValue = callback.call(null,accumulatorValue,this[i],i,this);
}
return accumulatorValue;
}
}
const numbers = [1,2,3,4,5];
console.log(numbers.customReduce((acc,num) => acc * num, 5)); // -> 600
As you see we can easily managed to implement these functions
by ourselves. If you have anything to add/edit please do not hesitate to share/comment.
You can also get these code snippets from github.
Stay tuned, bye bye.