Кратко
СкопированоИнструкция for
выполняет цикл обхода перечисляемых свойств объекта, включая перечисляемые свойства прототипов.
В каждой итерации цикла переменная цикла получает значение, соответствующее имени перечисляемого свойства объекта. Порядок обхода свойств строго определён спецификацией ECMAScript.
Перечисляемые свойства — это свойства, которые разработчик добавляет объекту.
В цикл for
не попадут: встроенные свойства, например, методы объекта, унаследованные от Object
, а также свойства, имена которых имеют тип Symbol
.
Как пишется
СкопированоСхематично структура для создания цикла выглядит так:
for (переменная in объект) { // Действия внутри цикла}
for (переменная in объект) { // Действия внутри цикла }
Для цикла необходимо объявить название переменной и указать сам объект, свойства которого нужно обойти. В объявленной переменной будет храниться имя свойства во время итерации:
const cat = { name: 'Борис', color: 'red', age: 8}for (const key in cat) { console.log(`${key} — ${cat[key]}`)}// name — 'Борис',// color — 'red',// age — 8
const cat = { name: 'Борис', color: 'red', age: 8 } for (const key in cat) { console.log(`${key} — ${cat[key]}`) } // name — 'Борис', // color — 'red', // age — 8
Как понять
СкопированоЦикл for
— это хороший способ пройти по всем свойствам объекта, но стоит помнить несколько важных особенностей.
Что такое перечисляемые свойства
СкопированоПеречисляемые свойства объекта — это свойства, которые явно помечены такими. Сказать свойству, что оно перечисляемое, можно через специальный метод define
. Для простоты все свойства, которые добавляются к объекту, являются перечисляемыми по умолчанию. Встроенные свойства не перечисляются. Например, метод index
у объекта String
или метод to
у любого объекта не участвует в цикле for
.
Цикл for
будет перебирать не только собственные свойства объекта, но и перечисляемые свойства, наследуемые от цепочки прототипов. Имена свойств в цикле не повторяются. Свойства объекта имеют наивысший приоритет, а свойства ближайших прототипов — больший приоритет над свойствами прототипов, находящихся дальше от объекта в его цепочке прототипов:
const grandParent = { a: 1, b: 2 }const parent = { b: 3, c: 4 }const object = { c: 5 }Object.setPrototypeOf(parent, grandParent)Object.setPrototypeOf(object, parent)for (const key in object) { console.log(key, object[key])}// c 5// b 3// a 1
const grandParent = { a: 1, b: 2 } const parent = { b: 3, c: 4 } const object = { c: 5 } Object.setPrototypeOf(parent, grandParent) Object.setPrototypeOf(object, parent) for (const key in object) { console.log(key, object[key]) } // c 5 // b 3 // a 1
Если несколько объектов в цепочке прототипов имеют свойство с одинаковым именем, будет учитываться только первое из них, и оно будет участвовать в цикле только в том случае, если перечисляемое. Если оно неперечисляемое, никакие другие свойства с таким же именем дальше по цепочке прототипов не будут участвовать в цикле, даже если они являются перечислимыми.
Порядок перечисления свойств
СкопированоСпецификация ECMAScript определяет следующий порядок обхода перечисляемых свойств объекта при выполнении цикла for
:
- Неотрицательные целочисленные ключи (те, которые могут быть индексами массива) в порядке возрастания значений.
- Строковые ключи в порядке возрастания хронологии создания.
В том же порядке будут перебираться свойства прототипов объекта.
Демонстрация порядка обхода целочисленных свойств:
const booksById = { 341: { name: 'Harry Potter' }, 144: { name: 'Flowers for Algernon' }, 202: { name: 'Lord of the Rings' }}for (const key in booksById) { console.log(key)}// 144// 202// 341
const booksById = { 341: { name: 'Harry Potter' }, 144: { name: 'Flowers for Algernon' }, 202: { name: 'Lord of the Rings' } } for (const key in booksById) { console.log(key) } // 144 // 202 // 341
Демонстрация порядка обхода объекта, имеющего строковые и символьные свойства:
const id = Symbol('id')const developer = { name: 'Ваня', language: 'JavaScript', [id]: '8888', company: 'Google'}developer.age = 33for (const key in developer) { console.log(key)}// name// language// company// age
const id = Symbol('id') const developer = { name: 'Ваня', language: 'JavaScript', [id]: '8888', company: 'Google' } developer.age = 33 for (const key in developer) { console.log(key) } // name // language // company // age
❗️ Использовать цикл for
для перебора массивов не рекомендуется по нескольким причинам:
- В цикл
for
попадут не только целочисленные свойства, но и строковые, а также наследуемые.. . . in - Переменная цикла на каждой итерации, соответствующая индексу текущего элемента, будет иметь тип строки, а не числа.
Для перебора у массива есть собственные методы: for
, map
и другие.
Изменение объекта во время выполнения цикла for...in
СкопированоПо возможности следует избегать изменения объекта при выполнении цикла.
Спецификация ECMAScript определяет случаи во время выполнения итерации, при которых алгоритм работы цикла может нарушаться:
- модификация цепочки прототипов;
- удаление свойства из объекта или из объектов в цепочке прототипов;
- добавление свойства объекту из цепочки прототипов;
- изменение атрибута
enumerable
у свойств объекта или в объектах из цепочки прототипов.
Подсказки
Скопировано💡 Для получения списка перечисляемых свойств только самого объекта, можно использовать статический метод Object
.