Сегодня исполняется 3 недели с тех пор, как я начал свой буткемп по разработке программного обеспечения. Одним из первых сценариев, на котором я зациклился, была работа с массивами и объектами и чувство разочарования при попытке доступа к информации в этих структурах данных.

Как только я полностью понял различие между тем, что является итерируемым и тем, что является перечисляемым, я стал более уверенно работать со сложными структурами данных. Я хотел написать этот пост в блоге, чтобы еще больше укрепить свое понимание этой темы, а также, надеюсь, помочь другому студенту, изучающему программную инженерию, когда-нибудь понять разницу.

Для начала, каково официальное определение этих терминов? Merriam-Webster дает следующие определения:

повторить: сказать или сделать снова или снова и снова
перечислить: установить количество или указать одно за другим

Из этих определений я понял, что итерация не так подробна и специфична, как перечисление. Когда мы итерируем, мы повторяем что-то, не заботясь о том, что это что-то есть на самом деле. Когда мы перечисляем, мы смотрим на каждую вещь и собираем информацию о ней. Представьте себе игрушечный ящик, полный собачьих игрушек. Если мы откроем крышку и попытаемся сосчитать каждую игрушку, не касаясь их, мы итерируем. Если мы вытащим каждую игрушку и посчитаем их, мы перечислим. Перечисление также дает нам возможность посмотреть на каждую игрушку и определить, какими свойствами обладает каждая игрушка, например, есть ли у нее пищалки?

Что это означает для JavaScript? Мы знаем, что объекты представляют собой пару данных ключ:значение, а массивы представляют собой набор данных. Эти данные могут быть строками, числами, логическими значениями и даже массивом объектов! Чтобы вернуться к нашему рабочему определению итерации и перечисления, я думаю об объектах как о более конкретной структуре данных, чем массивы. С объектом у нас есть пара ключ: значение (где мы даем ключу имя переменной), на которую мы можем ссылаться. В то время как массивы — это более простая структура данных, к которой мы обращаемся через их индекс.

Хотя технически… массив на самом деле является объектом, где ключ — это индекс, а значение — это то, что мы видим в массиве. Вы увидите это в действии ниже.

Давайте рассмотрим пример использования циклов JavaScript for…in и for…of. Эти циклы позволяют нам либо перебирать, либо перечислять набор данных.

Цикл for…in используется для перечисления. Мы можем использовать это для объектов и массивов.

Цикл for…of используется для итерации. Мы можем использовать это только для массивов.

Подумайте о нашей аналогии с игрушечной коробкой. Если я хочу осмотреть каждую игрушку, мне нужно зайти в ящик с игрушками. Если я просто хочу посмотреть игрушки, я открываю ее и проверяю в коробках.

Мы не можем перебирать объект, потому что нам нужно поближе рассмотреть объект, чтобы увидеть его свойства, а мы не можем сделать это, просто открыв коробку с игрушками и взглянув на игрушки. Давайте рассмотрим несколько реальных примеров кода с помощью JavaScript.

Здесь у нас есть массив с набором различных типов данных (строки, логическое значение и число), объект с несколькими парами ключ:значение и массив объектов. Давайте посмотрим, что происходит с каждой из этих структур данных с нашими разными циклами for!

for (const item of array) { 
 console.log(item) 
} 
// LOGGED: ‘cat’ 
// LOGGED: ‘dog’ 
// LOGGED: 22 
// LOGGED: true 
// LOGGED: ‘apples
for (const item in array) { 
 console.log(item) 
} 
// LOGGED: 0 
// LOGGED: 1 
// LOGGED: 2 
// LOGGED: 3 
// LOGGED: 4

Когда мы перебираем массив, мы получаем значения массива. Когда мы перечисляем массив, мы получаем индекс каждого значения. Давайте посмотрим, что происходит с нашим объектом!

for (const item of object) { 
 console.log(item) 
} 
// LOGGED: TypeError: object is not iterable
for (const item in object) { 
 console.log(item) 
} 
// LOGGED: number 
// LOGGED: name 
// LOGGED: age 
// LOGGED: isCool

Когда мы повторяем объект, мы получаем сообщение об ошибке «объект не является итерируемым», что теперь имеет смысл! Когда мы перечисляем объект, мы получаем ключи, но не значения. Интересно… Итак, мы рассмотрели предмет достаточно долго, чтобы увидеть, какими свойствами он обладает, но недостаточно хорошо, чтобы определить значение этих свойств. Если использовать аналогию с ящиком для игрушек, мы увидели, что у каждой игрушки есть пищалка, но не то, сколько пищалок у нее есть.

Для этого мы используем специальный метод Object.values(), который возвращает массив значений того, что передается внутри (). Мы также можем использовать Object.keys() для получения ключей и Object.entries() для получения ключа и значения.

Object.values(object) 
//=> [1, ‘Steve’, 31, true]
Object.keys(object) 
//=> [‘number’, ‘name’, ‘age’, ‘isCool’]
Object.entries(object) 
//=> [ 
      [‘number’, 1], 
      [‘name’, ‘Steve], 
      [‘age’, 31], 
      [‘isCool’, true] 
     ]

Это позволяет нам взять объект и, по сути, превратить его в массив, чтобы затем мы могли перебирать его. Важно отметить, что Object.entries() возвращает вложенный массив с парой ключ: значение, разделенной запятыми, а не двоеточием.

А как насчет нашего массива объектов? Что происходит, когда мы используем для этого циклы for?

for (const item of arrayOfObjects) { 
 console.log(item) 
} 
// LOGGED: { num: 1, name: ‘Steve’, age: 30, isCool: true } 
// LOGGED: { num: 2, name: ‘Jessica’, age: 28, isCool: true } 
// LOGGED: { num: 3, name: ‘Doyle’, age: ‘old’, isCool: true }
for (const item in arrayOfObjects) { 
 console.log(item) 
} 
// LOGGED: 0 
// LOGGED: 1 
// LOGGED: 2

Когда у нас есть массив, в котором значением каждого массива является объект, мы фактически используем for…of для возврата каждого объекта. Это имеет смысл, когда вы разбиваете его на части, но может сбивать с толку, когда вы смотрите на него и спрашиваете себя «как я могу получить эти объекты… мне нужно перечислить», когда вам действительно нужно выполнить итерацию, поскольку объекты вложены в массив. Когда мы используем for…in, мы просто получаем индекс каждого элемента в массиве.

Надеюсь, теперь у вас есть более глубокое понимание того, как и когда использовать итерацию и перечисление, что приведет к меньшему разочарованию при программировании!