JS Rewrited #01 - Array.map()

Summary

In this article, we will discuss what the Array.map function is, its usage, and recreate its behavior by creating a brand new custom function to get a deeper understanding of how it works in detail.

  1. The map function
  2. Usage
  3. Function rewriting
  4. Resources
  5. Conclusion

1. The map function

Array's map function is nothing more than a functional way to transform each one of the elements of an array into something else.

Basically, this function takes as input a callback function provided by the developer and an optional thisArg (value to be used as this by the callback). It has the following signature:

Array.map(callbackFn(currentElement, currentIndex, currentArray), thisArg)

It accepts two inputs:

  • callbackFn: a function provided by the developer to perform any operation in the element of the array. It must return the new intended value which the element is being mapped into. This function can receive three arguments:

    • currentElement : the current element being iterated.
    • currentIndex : the current index of the element being iterated.
    • currentArray : the current array object.
  • thisArg : the value used as this by the provided callbackFn. This is an optional argument.

The returned value of this function is a brand new array containing all the mapped elements.

2. Usage

In this simple example, a function to square a number was defined to be used as the map's callback. Given an array of numbers, each one of the elements will be mapped to its squared value in a brand new array as the result of the map operation.

For the sake of simplicity, the thisArg was omitted.

/* Defines a squaring function to be used as a callback argument */
function squareFn(currentElement, index, currentArray){
   return currentElement**2;
}

const numbers = [1, 2, 3, 4, 5];
const squaredNumbers = numbers.map(squareFn);
/* Prints the brand new generated list */
console.log(squaredNumbers);
/* output: [1, 4, 9, 16, 25] */

Interesting gotcha:

  • If you wish to use the optional parameter thisArg, be sure your callback function definition is done in the standard way (function myFunc(){}), not with an arrow function expression (const myFunc = () => {}). This is required for the binding of the custom this value to work properly inside the provided callback since the arrow function binds its context to its lexical scope.

3. Function rewriting

Have you ever wondered what kind of magic provides the argument's values to the callback function?

Knowing what the map function does, it is possible to recreate it with a new function that replicates its behavior to get a better understanding of how it works under the hood. This can be done by adding a new custom function to the javascript Array object with the following implementation:

Array.prototype.customMap = function(callback, thisArg) {
    /* Sets the "this" context to be used within the callback function, defaults to the array which this function was called. */
    const _this = thisArg || this;
    const mappedArr = [];
    /* For each element, the callback function is called passing the provided context for "this" keyword */
    for(let i = 0; i < this.length; i++) {
        mappedArr.push(callback.call(_this, this[i], i, this));
    }
    return mappedArr;
};

You can test the new customMap function by replacing the map call that was done previously. The same output should be displayed.

const squaredNumbers = numbers.customMap(squareFn);

PS.: This implementation might differ from the native one implemented by browsers.

4. Resources

For further reference:

5. Conclusion

This article aimed to give a deeper understanding of how the array's map function works under the hood. The "magic" under the map function was demystified by recreating its implementation according to the function's original behavior.