for...of

Iterating over enumerable properties of an iterable object.

Time to read: 6 min

Briefly

The for...of statement performs a loop that iterates over the enumerable properties of an iterable object.

An iterable object can be perceived as a collection of elements. Iterable objects include: Array, String, Map, Set, TypedArray, as well as array-like objects such as arguments and DOM collections.

In each iteration of the loop, instructions that can reference the value of the current element of the collection are executed.

Example

We output the result of dividing each element of the array by 2:

        
          
          const numbers = [28, 16, 32]for (const value of numbers) {  console.log(value/2)}// 14// 8// 16
          const numbers = [28, 16, 32]

for (const value of numbers) {
  console.log(value/2)
}
// 14
// 8
// 16

        
        
          
        
      

We output a formatted representation for the elements of a Map object:

        
          
          const skills = new Map()skills.set(1, 'JavaScript')skills.set(2, 'CSS')skills.set(3, 'PHP')for (let value of skills) {  console.log(`${value[0]}.`, value[1])}// 1. JavaScript// 2. CSS// 3. PHP
          const skills = new Map()

skills.set(1, 'JavaScript')
skills.set(2, 'CSS')
skills.set(3, 'PHP')

for (let value of skills) {
  console.log(`${value[0]}.`, value[1])
}
// 1. JavaScript
// 2. CSS
// 3. PHP

        
        
          
        
      

How to write

Iterating over the enumerable properties of an iterable object, where in each iteration:

  • variable receives the value of the current element of the collection;
  • an instruction is executed, which has access to the value of the variable.
        
          
          for (variable of iterable_object)  instruction
          for (variable of iterable_object)
  instruction

        
        
          
        
      

Iterating over the enumerable properties of an iterable object, where in each iteration:

  • variable receives the value of the current element of the collection;
  • a block of instructions is executed, which has access to the value of the variable.
        
          
          for (variable of iterable_object) {  block_of_instructions}
          for (variable of iterable_object) {
  block_of_instructions
}

        
        
          
        
      

A variable can be defined using let, const, and var, or can be declared beforehand using let and var. If the current element is an object or an array, destructuring assignment can be used:

        
          
          const skills = new Map()skills.set(1, 'JavaScript')skills.set(2, 'CSS')skills.set(3, 'PHP')for (let [key, value] of skills) {  console.log(`${key}.`, value)}// 1. JavaScript// 2. CSS// 3. PHP
          const skills = new Map()

skills.set(1, 'JavaScript')
skills.set(2, 'CSS')
skills.set(3, 'PHP')

for (let [key, value] of skills) {
  console.log(`${key}.`, value)
}
// 1. JavaScript
// 2. CSS
// 3. PHP

        
        
          
        
      

As a variable, a property of a previously created object can be used:

        
          
          const str = 'Rumpelstiltskin'const obj = {}for (obj.value of str) {  if (obj.value === 'n') {    console.log('There is an "n" here')  }}// There is an "n" here
          const str = 'Rumpelstiltskin'
const obj = {}

for (obj.value of str) {
  if (obj.value === 'n') {
    console.log('There is an "n" here')
  }
}
// There is an "n" here

        
        
          
        
      

The for...of loop can be interrupted using the break statement:

        
          
          const array = [1, true, null, {}]for (const value of array) {  if (value === null) {    break  }  console.log(value)}// 1// true
          const array = [1, true, null, {}]

for (const value of array) {
  if (value === null) {
    break
  }
  console.log(value)
}
// 1
// true

        
        
          
        
      

The continue statement allows moving to the next iteration, skipping the remaining instructions:

        
          
          const array = [1, true, null, {}]for (const value of array) {  if (value === null) {    continue  }  console.log(value)}// 1// true// {}
          const array = [1, true, null, {}]

for (const value of array) {
  if (value === null) {
    continue
  }
  console.log(value)
}
// 1
// true
// {}

        
        
          
        
      

How to understand

The for...of statement is similar to for...in in that it allows iterating over a collection. However, unlike for...in, for...of only iterates over the values of the iterable properties of the object itself.

Let’s compare behaviors:

        
          
          // Create an array and add a property name to itconst array = ['Fm', 'H', 'Cm7']array.name = 'array of chords'console.log(array)// ['Fm', 'H', 'Cm7', name: 'array of chords']// Loop through the array using for...infor (const item in array) {  console.log(item);}// 0// 1// 2// name// Loop through the array using for...offor (const value of array) {  console.log(value);}// Fm// H// Cm7
          // Create an array and add a property name to it
const array = ['Fm', 'H', 'Cm7']
array.name = 'array of chords'

console.log(array)
// ['Fm', 'H', 'Cm7', name: 'array of chords']

// Loop through the array using for...in
for (const item in array) {
  console.log(item);
}
// 0
// 1
// 2
// name

// Loop through the array using for...of
for (const value of array) {
  console.log(value);
}
// Fm
// H
// Cm7

        
        
          
        
      

The for...of statement allows using a single method to iterate over iterable objects of different types without the need to convert them to an array.

Tips

💡 With for...of, you can iterate over a manually created iterator:

        
          
          // Create an iterator from a String objectconst iterator = new String("");iterator[Symbol.iterator] = function () {  return {    _tick: 0,    next: function() {      if (this._tick >= 3) {        return { done: true }      }      this._tick++      return {        value: `I was called ${this._tick} times`,        done: false      }    },  }}for (const item of iterator) {  console.log(item)}// I was called 1 times// I was called 2 times// I was called 3 times
          // Create an iterator from a String object
const iterator = new String("");

iterator[Symbol.iterator] = function () {
  return {
    _tick: 0,
    next: function() {
      if (this._tick >= 3) {
        return { done: true }
      }

      this._tick++

      return {
        value: `I was called ${this._tick} times`,
        done: false
      }
    },
  }
}

for (const item of iterator) {
  console.log(item)
}
// I was called 1 times
// I was called 2 times
// I was called 3 times

        
        
          
        
      

💡 With for...of, you can iterate over a generator function:

        
          
          function* getLangs() {  yield 'java';  yield 'js';  yield 'rust';}const generator = getLangs()for (const item of generator) {  if (item === 'js') {    console.log('JavaScript is here!')    break  }}// JavaScript is here!
          function* getLangs() {
  yield 'java';
  yield 'js';
  yield 'rust';
}

const generator = getLangs()

for (const item of generator) {
  if (item === 'js') {
    console.log('JavaScript is here!')
    break
  }
}

// JavaScript is here!

        
        
          
        
      

💡 It should be noted that the generator cannot be used twice, even if the loop was interrupted using break. Let’s try to use the generator iteration twice, using the generator function from the previous example:

        
          
          const generator = getLangs()for (const item of generator) {  if (item === 'js') {    console.log('JavaScript is here!')    break  }}// JavaScript is here!// The iteration will yield nothingfor (const item of generator) {  console.log(item)}
          const generator = getLangs()

for (const item of generator) {
  if (item === 'js') {
    console.log('JavaScript is here!')
    break
  }
}
// JavaScript is here!

// The iteration will yield nothing
for (const item of generator) {
  console.log(item)
}