.map()

Collects a new array from the parts of the old one.

Time to read: 6 min

Briefly

The map() method allows transforming one array into another using callback functions. The passed function will be called for each element of the array in order. A new array will be collected from the results of the function calls.

Example

Let's create an array of squares:

        
          
          const nums = [1, 2, 3, 4, 5, 6, 7, 8, 9]const squares = nums.map(function (num) {  return num * num})console.log(squares)// [1, 4, 9, 16, 25, 36, 49, 64, 81]
          const nums = [1, 2, 3, 4, 5, 6, 7, 8, 9]

const squares = nums.map(function (num) {
  return num * num
})

console.log(squares)
// [1, 4, 9, 16, 25, 36, 49, 64, 81]

        
        
          
        
      

Or we can create an array of objects:

        
          
          const objects = nums.map(function (num) {  return {    field: num,  }})console.log(objects)// [//   { field: 1 },//   { field: 2 },//   ...//   { field: 9 }// ]
          const objects = nums.map(function (num) {
  return {
    field: num,
  }
})

console.log(objects)
// [
//   { field: 1 },
//   { field: 2 },
//   ...
//   { field: 9 }
// ]

        
        
          
        
      

Interactive example:

Open demo in the new window

How it works

Like other similar methods, map() requires a callback function that will return some value. This value will go into the final transformed array.

The function we pass to the map() method can accept three parameters:

  • item — the element of the array in the current iteration;
  • index — the index of the current element;
  • arr — the array itself that we are iterating over.

Let's sum the numbers, indices, and lengths of the array:

        
          
          const nums = [0, 1, 2, 3]const transformed = nums.map(function (num, index, arr) {  return num + index + arr.length})console.log(transformed)// [4, 6, 8, 10]
          const nums = [0, 1, 2, 3]

const transformed = nums.map(function (num, index, arr) {
  return num + index + arr.length
})

console.log(transformed)
// [4, 6, 8, 10]

        
        
          
        
      

How to understand

There are often situations where you need to create one array based on another array, somehow transforming the original values. This can be done using regular loops for or while:

        
          
          const nums = [1, 2, 3, 4, 5]const transformed = []for (let i = 0; i < nums.length; i++) {  const num = nums[i]  const item = `${i}-${num}`  transformed.push(item)}console.log(transformed)// ['0-1', '1-2', '2-3', '3-4', '4-5']
          const nums = [1, 2, 3, 4, 5]

const transformed = []

for (let i = 0; i < nums.length; i++) {
  const num = nums[i]
  const item = `${i}-${num}`
  transformed.push(item)
}

console.log(transformed)
// ['0-1', '1-2', '2-3', '3-4', '4-5']

        
        
          
        
      

The task is solved; however, like other built-in array methods, map() allows you to write code shorter and easier to understand:

        
          
          const nums = [1, 2, 3, 4, 5]const transformed = nums.map(function (num, i) {  return `${i}-${num}`})console.log(transformed)// ['0-1', '1-2', '2-3', '3-4', '4-5']
          const nums = [1, 2, 3, 4, 5]

const transformed = nums.map(function (num, i) {
  return `${i}-${num}`
})
console.log(transformed)
// ['0-1', '1-2', '2-3', '3-4', '4-5']

        
        
          
        
      

The result is the same, but the way is shorter and simpler.

Tips

💡 map() returns a new array, while the original array will not be changed.

💡 When working with map(), it is necessary to return a value from the callback function. If you do not return a value — for example, forgetting to handle some branch of the condition, the final array will contain undefined:

        
          
          const nums = [1, 2, 3, 4, 5]const transformed = nums.map(function (num) {  if (num <= 3) {    return "less"  }  // Forgot to handle this branch of the condition})console.log(transformed)// ['less', 'less', 'less', undefined, undefined]
          const nums = [1, 2, 3, 4, 5]

const transformed = nums.map(function (num) {
  if (num <= 3) {
    return "less"
  }
  // Forgot to handle this branch of the condition
})
console.log(transformed)
// ['less', 'less', 'less', undefined, undefined]

        
        
          
        
      

💡 The size of the array returned by map() always matches the size of the array being traversed.

💡 The callback function will be called only for elements with established values.

Let's create an array using the constructor by specifying the size of the array Array(length). All elements of this array are unfilled:

        
          
          const newArray = Array(5)console.log("Array size:", newArray.length);// Array size: 5console.log(newArray)// [<5 empty items>]
          const newArray = Array(5)
console.log("Array size:", newArray.length);
// Array size: 5
console.log(newArray)
// [<5 empty items>]

        
        
          
        
      

Let's try to use the map() method to set the index as the value of the element. As a result, the initedArray will remain as empty as the original newArray:

        
          
          const initedArray = newArray.map(function (item, index) {    console.log("element:", item)    return index})console.log(initedArray)// [<5 empty items>]
          const initedArray = newArray.map(function (item, index) {
    console.log("element:", item)
    return index
})

console.log(initedArray)
// [<5 empty items>]

        
        
          
        
      

To solve this problem, we can use destructuring of the original array:

        
          
          const newArray = Array(5)console.log("Array size:", newArray.length)// Array size: 5const initedArray = [ ...newArray ].map(function (item, index) {    console.log("element:", item)    return index})// element: undefined// element: undefined// element: undefined// element: undefined// element: undefinedconsole.log(initedArray)// [ 0, 1, 2, 3, 4 ]
          const newArray = Array(5)
console.log("Array size:", newArray.length)
// Array size: 5

const initedArray = [ ...newArray ].map(function (item, index) {
    console.log("element:", item)
    return index
})
// element: undefined
// element: undefined
// element: undefined
// element: undefined
// element: undefined

console.log(initedArray)
// [ 0, 1, 2, 3, 4 ]

        
        
          
        
      

💡 To fill an array with the same values, you can use the recipe Creating an array from a large number of repeating elements.

Passing context to the callback function

The second argument of map() can accept a value that will be passed as the execution context of the callback function:

        
          
          const nums = [1, 2, 3]const otherData = { delta: 5 }const transformed = nums.map(function (num) {  // this now refers to the object otherData  return num + this.delta}, otherData)console.log(transformed)// [ 6, 7, 8 ]
          const nums = [1, 2, 3]

const otherData = { delta: 5 }

const transformed = nums.map(function (num) {
  // this now refers to the object otherData
  return num + this.delta
}, otherData)

console.log(transformed)
// [ 6, 7, 8 ]

        
        
          
        
      

Note that arrow functions cannot change the execution context, so passing a second argument will have no effect:

        
          
          const nums = [1, 2, 3]const otherData = { delta: 5 }const transformed = nums.map((num) => {  // this.delta in this case equals undefined  return num + this.delta}, otherData)console.log(transformed)// [ NaN, NaN, NaN ]
          const nums = [1, 2, 3]

const otherData = { delta: 5 }

const transformed = nums.map((num) => {
  // this.delta in this case equals undefined
  return num + this.delta
}, otherData)

console.log(transformed)
// [ NaN, NaN, NaN ]

        
        
          
        
      

In practice

Advice 1

🛠 When working with React or another library similar to it, map() is the most common way to transform an array of data into components that will ultimately appear on the page:

        
          
          function SomeComponent() {  const items = ['This', 'is', 'map!']  return (    <div>      {items.map(item => <span>{item}</span>)}    </div>  )}
          function SomeComponent() {
  const items = ['This', 'is', 'map!']

  return (
    <div>
      {items.map(item => <span>{item}</span>)}
    </div>
  )
}

        
        
          
        
      

🛠 Since map() returns an array, we can continue to chain other array methods on the resulting array, including a new map(), continuing to transform new data:

        
          
          const nums = [1, 2, 3, 4, 5]const result = nums.map(...).filter(...).map(...)
          const nums = [1, 2, 3, 4, 5]

const result = nums.map(...).filter(...).map(...)