for...in

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

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

Кратко

Скопировано

for...in позволяет пройти в цикле по перечисляемым свойствам объекта, в том числе по свойствам из прототипа.

Перечисляемые свойства – это свойства, которые разработчик добавляет объекту. Встроенные свойства, например length у массива, не обходятся в цикле for...in.

Как пишется

Скопировано

Схематично структура для создания цикла выглядит так:

        
          
          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.

В цикле будут перечислены не только собственные свойства объекта, но и все перечисляемые свойства из прототипа объекта и прототипа прототипа и так далее:

        
          
          const a = { a: 1 }const b = { b: 2 }const c = { c: 3 }Object.setPrototypeOf(b, a)Object.setPrototypeOf(c, b)for (const key in c) {  console.log(key)}// Выведет: c, b, a
          const a = { a: 1 }
const b = { b: 2 }
const c = { c: 3 }

Object.setPrototypeOf(b, a)
Object.setPrototypeOf(c, b)

for (const key in c) {
  console.log(key)
}
// Выведет: c, b, a

        
        
          
        
      

Порядок перечисления

Скопировано

В стандарте языка нет описания того, как свойства должны перечисляться, потому порядок будет зависеть от реализации в конкретном движке браузера. Но есть базовые правила, которое можно встретить во всех браузерах:

1️⃣ Строковые имена свойств будут перечисляться в порядке их присвоения к объекту:

        
          
          const developer = {  name: 'Ваня',  language: 'JavaScript',  company: 'Google'}for (const key in developer) {  console.log(key)}// name// language// company
          const developer = {
  name: 'Ваня',
  language: 'JavaScript',
  company: 'Google'
}

for (const key in developer) {
  console.log(key)
}
// name
// language
// company

        
        
          
        
      

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

        
        
          
        
      

Изменение объекта во время перебора

Скопировано

Если во время выполнения for...in добавлять свойства в объект, то нет гарантии, что это свойство попадёт в цикл. Свойство, удалённое из объекта до того, как до него дошёл цикл, не будет участвовать в итерации.