Skip to content

Instantly share code, notes, and snippets.

@alexhawkins
Last active November 1, 2024 12:00
Show Gist options
  • Save alexhawkins/28aaf610a3e76d8b8264 to your computer and use it in GitHub Desktop.
Save alexhawkins/28aaf610a3e76d8b8264 to your computer and use it in GitHub Desktop.
Implementation of Native JavaScript Methods (forEach, Map, Filter, Reduce, Every, Some)
'use strict';
/*****************NATIVE forEACH*********************/
Array.prototype.myEach = function(callback) {
for (var i = 0; i < this.length; i++)
callback(this[i], i, this);
};
//tests
var arr = ['biggy smalls', 'bif tannin', 'boo radley', 'hans gruber'];
arr.myEach(function(word) {
console.log(word);
});
//biggy smalls
//bif tannin
//boo radley
//hans gruber
/*****************NATIVE MAP*************************/
Array.prototype.myMap = function(callback) {
arr = [];
for (var i = 0; i < this.length; i++)
arr.push(callback(this[i], i, this));
return arr;
};
//tests
var arrs = ['dic tanin', 'boo radley', 'hans gruber'];
var numbers2 = [1, 4, 9];
var goodT = arrs.myMap(function(n) {
return n;
});
var squareRoot = numbers2.myMap(function(num) {
return Math.sqrt(num);
});
console.log(goodT); // [ 'dic tanin', 'boo radley', 'hans gruber' ]
console.log(squareRoot); // [ 1, 2, 3 ]
/*****************NATIVE FILTER*************************/
Array.prototype.myFilter = function(callback, context) {
arr = [];
for (var i = 0; i < this.length; i++) {
if (callback.call(context, this[i], i, this))
arr.push(this[i]);
}
return arr;
};
//tests
var numbers = [1, 20, 30, 80, 2, 9, 3];
var newNum = numbers.myFilter(function(n) {
return n >= 10;
});
console.log(newNum); // [ 20, 30, 80 ]
/*****************NATIVE REDUCE*************************/
Array.prototype.myReduce = function(callback, initialVal) {
var accumulator = (initialVal === undefined) ? undefined : initialVal;
for (var i = 0; i < this.length; i++) {
if (accumulator !== undefined)
accumulator = callback.call(undefined, accumulator, this[i], i, this);
else
accumulator = this[i];
}
return accumulator;
};
//tests
var numbers3 = [20, 20, 2, 3];
var total = numbers3.myReduce(function(a, b) {
return a + b;
}, 10);
console.log(total); // 55
var flattened = [
[0, 1],
[2, 3],
[4, 5]
].reduce(function(a, b) {
return a.concat(b);
});
console.log(flattened); //[ 0, 1, 2, 3, 4, 5 ]
/*****************NATIVE EVERY*************************/
Array.prototype.myEvery = function(callback, context) {
for (var i = 0; i < this.length; i++) {
if (!callback.call(context, this[i], i, this))
return false;
}
return true;
};
//tests
var passed = [12, 5, 8, 130, 44].myEvery(function(element) {
return (element >= 10);
});
console.log(passed); // false
passed = [12, 54, 18, 130, 44].myEvery(function(element) {
return (element >= 10);
});
console.log(passed); // true
passed = [12, 54, 18, 130, 44].myEvery(function(element) {
return (element >= 13);
});
console.log(passed); // false
/*****************NATIVE SOME*************************/
Array.prototype.mySome = function(callback, context) {
for (var i = 0; i < this.length; i++) {
if (callback.call(context, this[i], i, this))
return true;
}
return false;
};
//tests
var passed = [12, 5, 8, 130, 44].mySome(function(element) {
return (element >= 200);
});
console.log('some: ' + passed); //some: false
var passed = [12, 5, 8, 130, 44].mySome(function(element) {
return (element >= 100);
});
console.log('some: ' + passed); //some: true
@fuermosi777
Copy link

line 66: why not just let accumulator = initialValue?

@onso89
Copy link

onso89 commented Dec 9, 2017

How can we check other methods on our own? How to find JS build in methods definitions?

@PranavRudra
Copy link

PranavRudra commented Jan 15, 2018

@Ghanshyam-K-Dobariya

You can solve that problem by doing

if (i in this)
  callback(this[i], i, this);

That way, since each array element's index is a property of the array, indices 3-9 won't result in undefined being printed

@mahmoudZakaria90
Copy link

@fuermosi777 or we can abstract it to
if(!accumulator)

@bassettyambica
Copy link

Awesome work!!

@martianmartian
Copy link

Many native array functions, including Array.map and Array.filter, are therefore written as pure functions. They take in an array reference and internally, they copy the array and work with the copy instead of the original.

https://codeburst.io/explaining-value-vs-reference-in-javascript-647a975e12a0

nice work but this isn't it

@martianmartian
Copy link

@Tellisense
Copy link

thank you very much!!

@prabhic
Copy link

prabhic commented Mar 21, 2018

Thanks for that, very easy to understand the behaviour, instead of reading a big document

@brinthsanti
Copy link

Its really useful bro....

@goelnavneet2006
Copy link

good job done!

@rakesh-nayak
Copy link

Very useful!!

@godblessmensah
Copy link

This goes to confirm this article javascript performance mistakes . Its more helpful to use the plain old for loop than the new array functions in es6.

@stanlee94
Copy link

Cool! Been looking for this for a while.

@usmanajmal
Copy link

usmanajmal commented Jan 26, 2019

@alexhawkins How do you use context in myFilter and why does your solution work when context is undefined as it is in your tests.

@supposedly
Copy link

supposedly commented Feb 4, 2019

@usmanajmal someFunction.call(), aka Function.prototype.call(), uses its first argument as "this". That means that callback.call(context, ...) is a direct equivalent to callback.bind(context)(...), which in turn says that any instances of this within callback will refer to context.

As you can probably tell, it has little to no relevance here... so TBQH I'm not quite sure why this gist's author used .call() in such a manner. Rather than defining myFilter(callback, context) and then doing callback.call(context, ...), it would be much preferable (as far as I can tell) to define myFilter(callback) and simply do callback(...); if the user needs to bind to context, they can pass the callback in as callback.bind(context) without forcing the myFilter function to care about it.
(Same goes for myReduce()... would be simpler within it to do callback(...) rather than callback.call(undefined, ...).)

@ved740
Copy link

ved740 commented Mar 13, 2019

Wow.. You made it look so easy !! GREAT

@kshitijnagpal
Copy link

Good work, thanks!

@sagarrock101
Copy link

what has "callback(this[i], i, this)"; have to do in the code??

@ankitsny
Copy link

ankitsny commented Jul 8, 2019

thanks,

@ankitsny
Copy link

ankitsny commented Jul 8, 2019

Can you explain how Map data structure is implemented in JS, Considering Non-Primitive data type as key.

@priyankamalviya
Copy link

everything looks great except, in reduce, why do we need all these parameters when we are binding the reduceFn context? [undefined, accumulator, this[i], i, this]? Any explanations please? I noticed, this breaks without the undefined

@NexGenUA
Copy link

NexGenUA commented Oct 4, 2019

myReduce function is wrong

[undefined,null,'3',4,5].reduce((acc, cur) => acc*cur) // NaN; 
[undefined,null,'3',4,5].myReduce((acc, cur) => acc*cur) // 0;

correct:

Array.prototype.myReduce = function(...rest) {
  
  if (!rest || typeof rest[0] !== 'function') {
    throw new TypeError(`${rest[0]} is not a function`);
  }

  const callback = rest[0];
  const arr = this;
  let thumb = rest.length > 1;
  let accumulator = thumb ? rest[1] : arr[0];

  for (let i = 0; i < arr.length; i++) {
    if (thumb) {
      accumulator = callback(accumulator, arr[i], i, arr);
    } else thumb = true;
  }
  return accumulator;  
}

@vihangmi10
Copy link

Thanks for helping us out! Great one!

@abhijithsreenivas
Copy link

Seriously Great one ☝️. Thanks!

@jialihan
Copy link

jialihan commented Mar 7, 2021

My reduce implement: just a little bit difference:

Array.prototype.myReduce = function (fn, initialValue) {
    var accumulator = initialValue || this[0];
    for (var i = 0; i < this.length; i++) {
        if (!initialValue && i === 0) {
            // when initialValue is not provided
            continue;
        }
        accumulator = fn.call(null, accumulator, this[i], i, this);
    }
    return accumulator;
};

@mAminP
Copy link

mAminP commented Aug 27, 2021

Good work, thanks!

@hs2504785
Copy link

Very nice

@bookuha
Copy link

bookuha commented Sep 1, 2022

else
accumulator = this[i]; at line 70
is not like this in current native reduce,
this one will omit undefined values at any step and proceed to this[i]
the native one will sum it up, it will use this check for initial value just once

Thank you!

Array.prototype.myReduce = function(callback, initialVal) {
   
    if(initialVal !== undefined) accumulator = initialVal;
    else accumulator = this[i++];
        
    for (var i = 0; i < this.length; i++) {
            accumulator = callback.call(undefined, accumulator, this[i], i, this);
    }
    return accumulator;
};

@VladSemenik
Copy link

VladSemenik commented Feb 2, 2024

@alexhawkins Bro, what will happen to your methods which are binding context if you pass arrow function () => {}. I do think it is not gonna work.

I deleted my smiles because I thought specific bug in your implementation, but js filter works as same as yours. So I guess thats why none uses it. 😅 This one I had to add.

`Array.prototype.myFilter = function(callback, context) {
arr = [];
for (var i = 0; i < this.length; i++) {
if (callback.call(context, this[i], i, this))
arr.push(this[i]);
}
return arr;
};

[].myFilter.call([1,2,3], (e) => {
console.log(this.isItWorking)
return e % 2 === 0
}, {isItWorking: "mmmm..."})`

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment