Everything you needed to know and more about Array.map
Tags: javascript, map, codedeepdives, v8
Published: 2020-01-08 21:35:51

---
title: Everything you needed to know and more about Array.map
published: true
description: A blog post diving into the history and nitty-gritty details of the oft-used Array.map method in JavaScript.
tags: javascript, map, code-deep-dives, v8
series: Code Deep Dives
---

As a developer, I find myself reaching for the `Array.map` method frequently in my JavaScript code. It seems that there's always a list of something to run through when building web apps.

Tangent: I'd argue that the entire field of computer science is about managing lists of things but that's another blog post for another day.

Like any helpful piece of software, it's sometimes easy to forget where it came from and how exactly it got to be so notorious.  I decided to take this as an opportunity to learn more about `Array.map`. If you're familiar with my blog posts, you probably know where this is headed... :)

## What is `Array.map`?

`Array.map` is a function that takes a list and a callback as parameters and returns a new list with the callback applied to each item in the original list. Nice and simple. Here's an example of a map used to double the values of each item in a list.

```javascript
> const numbers = [0, 1, 2, 3, 4];
> const doubled = numbers.map(function(value) {
  return value * 2;
});
> console.log(doubled);
```

Per the [official ECMAScript specification for Array.map](https://www.ecma-international.org/ecma-262/6.0/#sec-array.prototype.map), the callback provided to the `map` function takes three parameters: the current value in the iteration loop, the index of that value, and the array.

## When should `Array.map` be used?

`Array.map` should be used in scenarios where a new output array needed to be generated from the input array. For scenarios where you want to modify the input array or not return anything at all, it's a better idea to use `forEach`. I'll admit that I'm guilty of misusing `map` quite often. I suspect that this is because I spent most of my time working with immutable data structures where no mutations happen on input data so I'm used to using `map` in scenarios where `forEach` would make more sense.

## A history of map

How did `map` became a part of the JavaScript programming language and indeed many other programming languages? Unsurprisingly, it has its roots in mathematics. In mathematics, a map is a general function that translates values in one mathematical structure to values in another.

Map functions made the jump from mathematics to computer science in 1959 in an implementation of the Lisp programming language. The original `map` function in Lisp was implementation in a standard function called `mapList`. As newer programming languages emerged, the usefulness of `map` was carried from Lisp to newer languages.

## Under the hood with an Array.map implementation

The link to the ECMAScript specification above provides a description of the algorithm that JavaScript engines are expected to implement in their `Array.map` implementations. I decided to take a look at the V8 implementation of a map and the corresponding pseudocode from the specification algorithm. After some digging around, I was able to trace where different parts of the algorithm outlined above where happening in the V8 codebase. Now, I don't spend a lot of time reading C++ code and I am not as familiar with the patterns that the V8 engine uses to represent list-like data structures. Nonetheless, I was able to muddle my way through and correlate some parts of the standardized algorithm to the implement in V8. Feel free to correct or fill in more in the comments!

| Psuedocode                                                         | Description                                                                                        | Implementation                                                                                                              |
|--------------------------------------------------------------------|----------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------|
| Let O be ToObject(this value)                                      | Converts the input value to an Object type.                                                        | [link](https://github.com/v8/v8/blob/4b9b23521e6fd42373ebbcb20ebe03bf445494f9/src/builtins/builtins-array-gen.cc#L154-L155)      |
| ReturnIfAbrupt(O)                                                  | Checks to see if the input value is an "empty" value like undefined or an empty string.            | [link](https://github.com/v8/v8/blob/4b9b23521e6fd42373ebbcb20ebe03bf445494f9/src/builtins/builtins-array-gen.cc#L159)      |
| Let len be ToLength(Get(O, "length"))                              | Get the length of the input object so it can be used to build a new array.                         | [link](https://github.com/v8/v8/blob/4b9b23521e6fd42373ebbcb20ebe03bf445494f9/src/builtins/builtins-array-gen.cc#L161)      |
| ReturnIfAbrupt(len)                                                | Checks to see if the length is some zero or null value.                                            |                                                                                                                             |
| If IsCallable(callbackfn) is false, throw a TypeError exception    | Checks to see if the callback can be invoked                                                       | [link](https://github.com/v8/v8/blob/4b9b23521e6fd42373ebbcb20ebe03bf445494f9/src/builtins/builtins-array-gen.cc#L165-L167) |
| If thisArg was supplied, let T be thisArg; else let T be undefined | Sets the value of `this` in the scope of the callback if given.                                    |                                                                                                                             |
| Let A be ArraySpeciesCreate(O, len)                                | Creates a new array of length `len` that will be created.                                          |                                                                                                                             |
| ReturnIfAbrupt(A)                                                  | Checks to see if an empty array was created.                                                       |                                                                                                                             |
| Let k be 0. Loop from k to len building A                          | Iterate through the input array and build the output array by invoking the callback on each value. | [link](https://github.com/v8/v8/blob/4b9b23521e6fd42373ebbcb20ebe03bf445494f9/src/builtins/builtins-array-gen.cc#L216)      |


Note that since the algorithm implemented in the standard is, well, the standard that other JavaScript engines will implement the same algorithm.

And that's that on `map`.  Do you leverage `map` heavily in your code? Do you feel that using `map` has encourage you to write code that leverages more immutable data structures?