Building the Javascript .map() function from scratch

Probably one of the most used and most powerful functions ( .reduce() might be the most important) in the Javascript language is the .map() function (And let’s not forget it’s somewhat closely related cousin .forEach()). Both of these functions allow us to iterate over an array and do something with each element one by one.

First, what is the difference between map and forEach in Javascript?

.map() – Iterates over a collection and does something to each item and then pushes that new element to a newly created array which is then returned once each element in the provided collection has been iterated over.

.forEach() – Still iterates over a collection and does something to each item but it does not push the returned value of the action to a new array. (Think: “for each element in this array, go off an fire of an XHR and get the response and do something with it”… Have fun with all of the promises!)

Let’s recreate .map() from scratch

When writing software we take for granted what is going on under the hood in the built in methods and functions Javascript provides to us (Really any language, for that matter). By re-creating .map() from scratch will give us a better understanding of how the code is behaving in our applications. From there we can start building on that knowledge to understand more advanced topics like how the reduce function works.

Remember: .map() allows us to go through each element in a collection (array) and does something to each element (it ‘maps it’ to a new value based on the instructions we give it) and then returns an array with all the new values.

A few things stick out right away with the above breakdown:

  • Our custom map function will have two parameters:
    • The input collection (array)
    • Instructions (a callback function) that we pass in
  • Our custom map function will also need a way to iterate over each element – So we’ll have to employ some kind of loop to achieve this
  • We’re returning a new array – at some point we’re going to have to create a new array

Ready? Here’s essentially what map is doing under the hood:

const arr = [1, 2, 3, 4, 5];

const newMap = (input, mutator) => {
  let newArr = [];
  for (let i = 0; i < input.length; i++) {
    newArr.push(mutator(input[i]));
  }
  return newArr;
};
const multiplyByTwo = (num) => {
  return num * 2;
};

const answer = newMap(arr, multiplyByTwo);

console.log(answer);

Line 1 we’re declaring a constant in memory with the label arr and assigning it the value [1, 2, 3, 4, 5].

Line 3 we’re defining a function in memory with the label newMap.

Line 10 we’re again defining a function in memory with the label multiplyByTwo.

And finally, line 14 we are declaring a constant in memory and assigning it the value to whatever the code to the right of the equals sign evaluates to – this is where we invoke/run the code above.

To the right of the equals sign on line 14 we run the newMap function and we provide it with two arguments: arr and the function multiplyByTwo.

We then create a new local execution context when we start running the newMap function where we setup our parameters:

input: [1, 2, 3, 4, 5]
mutator: (num) => { return num * 2 }

Next, we create a new empty array giving it the label newArr.

The provided array, now known as input in this local execution context, is then iterated over using a for loop. For each element in the collection, we then run the multiplyByTwo function with the input, which then returns the input number multiplied by 2 and that number is then pushed into the previously created new blank array (newArr).

Finally, once the for loop completes, the function then runs the last line of code which is to “spit out” (return) the newly created array and store that into the variable answer where we then console.log it to see it’s value.

Closing thoughts

Recreating the map function is a great exercise for newer developers because it allows you to “peel back the layers” of what’s going on under the hood in some of the code you’ve been working with for several months or years. Furthermore, doing this also gives you a better understanding of how functional programming in Javascript works and by understanding how .map() works under the hood you will have a much better understanding of how .reduce() is working which is the cornerstone of functional programming.