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"

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

Специфікація
ECMAScript (ECMA-262)
The definition of 'for...in statement' in that specification.

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

Update compatibility data on GitHub
DesktopMobileServer
ChromeEdgeFirefoxInternet ExplorerOperaSafariAndroid webviewChrome for AndroidFirefox for AndroidOpera for AndroidSafari on iOSSamsung InternetNode.js
for...inChrome Full support 1Edge Full support 12Firefox Full support 1IE Full support 6Opera Full support 2Safari Full support 1WebView Android Full support 1Chrome Android Full support 18Firefox Android Full support 4Opera Android Full support 10.1Safari iOS Full support 1Samsung Internet Android Full support 1.0nodejs Full support 0.1.100

Legend

Full support  
Full support

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

До 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), також проводять дослідження щодо прибирання цієї нестандартної поведінки.

Див. також