for...in

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

Синтаксис

for (variable in object)
  statement
variable
Нове ім'я властивості призначається параметру variable на кожній ітерації.
object
Об'єкт, чиї не символьні перелічувані властивості перебираються.

Опис

Цикл for...in перебирає лише перелічувані, не символьні властивості. Об'єкти, створені вбудованими конструкторами, як Array та Object, успадковують неперелічувані властивості від Object.prototype та String.prototype, такі як метод indexOf() у String або метод toString() у Object. Цикл перебиратиме усі особисті перелічувані властивості об'єкта й ті, які об'єкт успадковує від прототипу конструктора (властивості, розташовані ближче до об'єкта у ланцюжку прототипів, заміщують властивості прототипу).

Видалені, додані або модифіковані властивості

Цикл for...in перебирає властивості об'єкта у довільному порядку (дивіться оператор delete, щоб дізнатись, чому не можна покладатися на удавану впорядкованість перебору, принаймні, у кросбраузерних налаштуваннях).

Якщо властивість була змінена під час однієї ітерації і потім відвідується під час наступної, її значенням у циклі буде значення під час наступної ітерації. Властивість, що була видалена до того, як була відвідана, не буде відвідана пізніше. Властивості, додані до об'єкта під час поточного перебору, можуть бути або відвідані, або пропущені під час цього перебору.

Загалом, краще не додавати, не змінювати й не видаляти властивості об'єкта під час перебору, окрім властивості, що відвідується у даний момент. Немає гарантії, що додана властивість буде відвідана, чи що змінена властивість (якщо це не поточна властивість) буде відвідана до чи після того, як була змінена, чи що видалена властивість не була відвідана до того, як була видалена.

Перебір масиву та for...in

Заувага: цикл for...in не слід використовувати для перебору масиву, де порядок індексів є важливим.

Індекси масивів є просто перелічуваними властивостями з цілочисельними іменами, в усьому іншому вони ідентичні загальним властивостям об'єкта. Немає гарантій, що for...in поверне індекси у певному порядку. Цикл for...in поверне усі перелічувані властивості, в тому числі не цілочисельні імена та успадковані властивості.

Оскільки порядок перебору залежить від реалізації, перебір масиву може відвідувати елементи масиву непослідовно. Тому краще використовувати цикл for з числовим індексом (або Array.prototype.forEach() чи for...of) для перебору масивів, коли порядок звернення до елементів важливий.

Перебір лише особистих властивостей

Якщо ви бажаєте розглядати властивості, притаманні лише самому об'єкту, а не його прототипам, скористайтесь getOwnPropertyNames() або виконайте перевірку hasOwnProperty() (також можна використати propertyIsEnumerable()). Альтернативно, якщо ви певні, що не буде зовнішнього втручання у код, ви можете розширити вбудовані прототипи методом перевірки.

Навіщо використовувати for...in?

Враховуючи, що цикл for...in створений для перебору властивостей об'єкта, не рекомендований для використання у масивах, і що існують такі варіанти як Array.prototype.forEach() та for...of, яка взагалі може бути користь від for...in?

Він може бути найбільш практичним для налагодження, оскільки ним легко перевіряти властивості об'єкта (виводячи їх у консоль чи іншим чином). Хоча масиви часто більш зручні для зберігання даних, у ситуаціях, де для роботи з даними потрібні пари ключ-значення (де властивості виконують роль "ключів"), можливі випадки, коли ви захочете перевірити, чи містить якийсь з цих ключів певне значення.

Приклади

Використання for...in

Наведений цикл for...in перебирає усі перелічувані, не символьні властивості об'єкта та виводить рядки імен властивостей та їхніх значень.

var obj = {a: 1, b: 2, c: 3};

for (const prop in obj) {
  console.log(`obj.${prop} = ${obj[prop]}`);
}

// Виведе:
// "obj.a = 1"
// "obj.b = 2"
// "obj.c = 3"

Перебір особистих властивостей

Наступна функція ілюструє використання hasOwnProperty(): успадковані властивості не виводяться.

var triangle = {a: 1, b: 2, c: 3};

function ColoredTriangle() {
  this.color = 'red';
}

ColoredTriangle.prototype = triangle;

var obj = new ColoredTriangle();

for (const prop in obj) {
  if (obj.hasOwnProperty(prop)) {
    console.log(`obj.${prop} = ${obj[prop]}`);
  }
}

// Виведе:
// "obj.color = red"

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

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

BCD tables only load in the browser

Сумісність: Ініціалізація лічильника у строгому режимі

До Firefox 40 було можливо використати ініціалізацію лічильника (i=0) у циклі for...in:

var obj = {a: 1, b: 2, c: 3};
for (var i = 0 in obj) {
  console.log(obj[i]);
}
// 1
// 2
// 3

Ця нестандартна поведінка тепер ігнорується у версії 40 та пізніших і викличе помилку SyntaxError ("for-in loop head declarations may not have initializers") у строгому режимі (bug 748550 та bug 1164741).

Інші рушії, такі як v8 (Chrome), Chakra (IE/Edge) та JSC (WebKit/Safari), також проводять дослідження щодо прибирання цієї нестандартної поведінки.

Див. також