Клавиша / esc

for...in

Обходим имена перечисляемых свойств объекта.

Время чтения: меньше 5 мин

Кратко

Скопировано

Инструкция for...in выполняет цикл обхода перечисляемых свойств объекта включая перечисляемые свойства прототипов.

В каждой итерации цикла переменная цикла получает значение соответствующее имени перечисляемого свойства объекта. Порядок обхода свойств строго определён спецификацией ECMAScript.

Перечисляемые свойства – это свойства, которые разработчик добавляет объекту.

В цикл for...in не попадут: встроенные свойства, например методы объекта унаследованные от Object.prototype, а также свойства имена которых имеют тип 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...in — это хороший способ пройти по всем свойствам объекта, но стоит помнить несколько важных особенностей.

Что такое перечисляемые свойства

Скопировано

Перечисляемые свойства объекта – это свойства, которые явно помечены такими. Сказать свойству, что оно перечисляемое, можно через специальный метод defineProperty(). Но для простоты все свойства, которые добавляются к объекту, являются перечисляемыми по умолчанию. Встроенные свойства не перечисляется. Например, метод indexOf() у объекта String или метод toString() у любого объекта не участвуют в цикле for...in.

Цикл for...in будет перебирать не только собственные свойства объекта, но и перечисляемые свойства наследуемые от цепочки прототипов. Имена свойств в цикле не повторяются (свойства объекта имеют наивысший приоритет, а свойства ближайших прототипов имеют больший приоритет над свойствами прототипов, находящихся дальше от объекта в его цепочке прототипов). :

        
          
          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...in:

  1. неотрицательные целочисленные ключи (те, которые могут быть индексами массива) в порядке возрастания значений.
  2. строковые ключи в порядке возрастания хронологии создания.

В том же порядке будут перебираться свойства прототипов объекта.

Демонстрация порядка обхода целочисленных свойств:

        
          
          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...in

Скопировано

По-возможности следует избегать изменения объекта при выполнении цикла.

Спецификация ECMAScript определяет случаи во время выполнения итерации при которых алгоритм работы цикла может нарушаться:

  • модификация цепочки прототипов.
  • удаление свойства из объекта или из объектов в цепочке прототипов.
  • добавление свойства объекту из цепочки прототипов.
  • изменение атрибута enumerable у свойств объекта или в объектах из цепочки прототипов.

Подсказки

Скопировано

💡 Для получения списка перечисляемых свойств только самого объекта можно использовать статический метод Object.keys()