for...of

Конструкція for...of створює цикл, що перебирає ітерабельні об'єкти, в тому числі: вбудовані String, Array, подібні до масиву об'єкти (наприклад, arguments або NodeList), TypedArray, Map, Set, а також визначені користувачем ітерабельні об'єкти. Він викликає користувацький хук до ітерацій з командами, що виконуються для значення кожної окремої властивості об'єкта.

Синтаксис

for (variable of iterable) {
  statement
}
variable
На кожній ітерації параметру variable призначається значення іншої властивості. Параметр variable може бути оголошений через const, let або var.
iterable
Об'єкт, чиї ітерабельні властивості перебираються.

Приклади

Перебір об'єкта Array

let iterable = [10, 20, 30];

for (let value of iterable) {
  value += 1;
  console.log(value);
}
// 11
// 21
// 31

Ви також можете використати const замість let, якщо не переприсвоюєте змінну всередині блоку.

let iterable = [10, 20, 30];

for (const value of iterable) {
  console.log(value);
}
// 10
// 20
// 30

Перебір об'єкта String

let iterable = 'фух';

for (let value of iterable) {
  console.log(value);
}
// "ф"
// "у"
// "х"

Перебір об'єкта TypedArray

let iterable = new Uint8Array([0x00, 0xff]);

for (let value of iterable) {
  console.log(value);
}
// 0
// 255

Перебір об'єкта Map

let iterable = new Map([['а', 1], ['б', 2], ['в', 3]]);

for (let entry of iterable) {
  console.log(entry);
}
// ['а', 1]
// ['б', 2]
// ['в', 3]

for (let [key, value] of iterable) {
  console.log(value);
}
// 1
// 2
// 3

Перебір об'єкта Set

let iterable = new Set([1, 1, 2, 2, 3, 3]);

for (let value of iterable) {
  console.log(value);
}
// 1
// 2
// 3

Перебір об'єкта arguments

Ви можете перебирати об'єкт arguments, щоб дослідити усі параметри, передані у функцію JavaScript:

(function() {
  for (let argument of arguments) {
    console.log(argument);
  }
})(1, 2, 3);

// 1
// 2
// 3

Перебір колекції DOM-елементів

Перебір колекцій DOM-елементів, таких як NodeList: наступний приклад додає клас read до вузлів paragraph, які є прямими нащадками вузла article:

// Заувага: Це працюватиме лише у платформах, де
// реалізовано NodeList.prototype[Symbol.iterator]
let articleParagraphs = document.querySelectorAll('article > p');

for (let paragraph of articleParagraphs) {
  paragraph.classList.add('read');
}

Закриття ітераторів

У циклах for...of раптове переривання ітерації може бути спричинено операторами break, throw або return. У цих випадках ітератор закривається.

function* foo(){ 
  yield 1; 
  yield 2; 
  yield 3; 
}; 

for (let o of foo()) { 
  console.log(o); 
  break; // закриває ітератор, виконання продовжується поза циклом
}
console.log('done');

Перебір генераторів

Ви також можете перебирати генератори, тобто, функції, що генерують ітерабельні об'єкти:

function* fibonacci() { // функція-генератор
  let [prev, curr] = [0, 1];
  while (true) {
    [prev, curr] = [curr, prev + curr];
    yield curr;
  }
}

for (let n of fibonacci()) {
  console.log(n);
  // обрізати послідовність на 1000
  if (n >= 1000) {
    break;
  }
}

Не використовуйте генератори повторно

Генератори не можна використовувати повторно, навіть якщо цикл for...of завчасно перервався, наприклад, ключовим словом break. На виході з циклу генератор закривається, і спроби викликати його знову не дадуть подальших результатів.

let gen = (function *(){
  yield 1;
  yield 2;
  yield 3;
})();
for (let o of gen) {
  console.log(o);
  break;  // закриває ітератор
}

// Генератор не можна використовувати знову, наступне не має сенсу!
for (let o of gen) {
  console.log(o); // Ніколи не виконається.
}

Перебір інших ітерабельних об'єктів

Ви також можете перебирати об'єкт, який відкрито реалізує протокол ітерабельного:

let iterable = {
  [Symbol.iterator]() {
    return {
      i: 0,
      next() {
        if (this.i < 3) {
          return { value: this.i++, done: false };
        }
        return { value: undefined, done: true };
      }
    };
  }
};

for (let value of iterable) {
  console.log(value);
}
// 0
// 1
// 2

Різниця між for...of та for...in

І цикл for...in, і цикл for...of щось перебирають. Головна різниця між ними полягає в тому, що саме вони перебирають.

Цикл for...in перебирає перелічувані властивості об'єкта, у довільному порядку.

Цикл for...of перебирає значення, які ітерабельний об'єкт визначає для перебирання.

Наступний приклад демонструє різницю між циклом for...of та циклом for...in при використанні з масивом.

Object.prototype.objCustom = function() {}; 
Array.prototype.arrCustom = function() {};

let iterable = [3, 5, 7];
iterable.foo = 'привіт';

for (let i in iterable) {
  console.log(i); // виведе 0, 1, 2, "foo", "arrCustom", "objCustom"
}

for (let i in iterable) {
  if (iterable.hasOwnProperty(i)) {
    console.log(i); // виведе 0, 1, 2, "foo"
  }
}

for (let i of iterable) {
  console.log(i); // виведе 3, 5, 7
}

Розглянемо наведений код крок за кроком.

Object.prototype.objCustom = function() {};
Array.prototype.arrCustom = function() {}; 

let iterable = [3, 5, 7]; 
iterable.foo = 'привіт';

Кожний об'єкт успадковуватиме властивість objCustom і кожний об'єкт, що є об'єктом Array, успадковуватиме властивість arrCustom, оскільки ці властивості були додані у Object.prototype та Array.prototype відповідно. Об'єкт iterable успадковує властивості objCustom та arrCustom через наслідування та ланцюжок прототипів.

for (let i in iterable) {
  console.log(i); // виведе 0, 1, 2, "foo", "arrCustom", "objCustom" 
}

Цей цикл виводить тільки перелічувані властивості об'єкта iterable, у довільному порядку. Він не виводить елементи масиву 3, 5, 7 або привіт, оскільки вони не є перелічуваними властивостями, власне, вони взагалі не є властивостями, вони є значеннями. Цикл виводить індекси масиву, а також arrCustom та objCustom, які є властивостями. Якщо ви не певні, чому ці властивості перебираються, є більш детальне пояснення того, як працює перебір масиву та for...in.

for (let i in iterable) {
  if (iterable.hasOwnProperty(i)) {
    console.log(i); // виведе 0, 1, 2, "foo"
  }
}

Цей цикл схожий на перший, але використовує hasOwnProperty() для перевірки, чи є знайдена перелічувана властивість особистою властивістю об'єкта, тобто, не успадкованою. Якщо є, властивість виводиться. Властивості 0, 1, 2 та foo виводяться, оскільки вони є особистими властивостями (не успадкованими). Властивості arrCustom та objCustom не виводяться, оскільки вони успадковані.

for (let i of iterable) {
  console.log(i); // виведе 3, 5, 7 
}

Цей цикл перебирає та виводить значення, які iterable як ітерабельний об'єкт визначає для перебору. Елементи об'єкта 3, 5, 7 виводяться, але немає жодної з властивостей об'єкта.

Специфікації

Специфікація Статус Коментар
ECMAScript 2015 (6th Edition, ECMA-262)
The definition of 'for...of statement' in that specification.
Standard Початкове визначення.
ECMAScript Latest Draft (ECMA-262)
The definition of 'for...of statement' in that specification.
Draft

Сумісність з веб-переглядачами

Update compatibility data on GitHub
DesktopMobileServer
ChromeEdgeFirefoxInternet ExplorerOperaSafariAndroid webviewChrome for AndroidFirefox for AndroidOpera for AndroidSafari on iOSSamsung InternetNode.js
for...ofChrome Full support 38Edge Full support 12Firefox Full support 13
Notes
Full support 13
Notes
Notes Prior to Firefox 51, using the for...of loop construct with the const keyword threw a SyntaxError ("missing = in const declaration").
IE No support NoOpera Full support 25Safari Full support 8WebView Android Full support 38Chrome Android Full support 38Firefox Android Full support 14
Notes
Full support 14
Notes
Notes Prior to Firefox 51, using the for...of loop construct with the const keyword threw a SyntaxError ("missing = in const declaration").
Opera Android Full support 25Safari iOS Full support 8Samsung Internet Android Full support Yesnodejs Full support Yes
async iteratorsChrome Full support 63Edge Full support 12Firefox Full support 57IE No support NoOpera Full support 50Safari ? WebView Android Full support 63Chrome Android Full support 63Firefox Android Full support 57Opera Android Full support 46Safari iOS ? Samsung Internet Android Full support 8.0nodejs ?
Closing iteratorsChrome Full support 51Edge Full support 14Firefox Full support 53IE No support NoOpera Full support YesSafari Full support YesWebView Android Full support YesChrome Android Full support 51Firefox Android Full support 53Opera Android Full support YesSafari iOS Full support YesSamsung Internet Android Full support Yesnodejs Full support Yes

Legend

Full support  
Full support
No support  
No support
Compatibility unknown  
Compatibility unknown
See implementation notes.
See implementation notes.

Див. також