Цикли for..in и for..of в JS

Цикл for является самым базовым методом итерирование массивов в JS. Он принимает три выражения: инициализация счетчика проверка условия остановки и изменения индекса.

Например, нам нужно вывести значение элементов массива

let arr=['angular','typescript','react'];
for(let index=0;i <arr.length;index++){
console.log(arr[index]);
}
// Result angular, typescript, react

Но в ES6 было добавлено два новых способа обойти массив с использованием цикла for. Эти методы называется for of и for in.

Цикл for…in

for…in используется для итерирования перечисляемых («enumerable») свойств объекта. Он применим ко всем объектам что имеют такие свойства.
Перечисляемое свойство — это такое свойство объекта, для которого параметр Enumerable установлен в true.

Синтаксис for…in

let rectangle={
    height:100,
    width:200
}
for(let prop in rectangle){
console.log(`${prop}=${rectangle[prop]}`)
}
// result
height=100
width=200

Стоит заметить что цикл for in также проходит по унаследованным свойствам, если они перечисляемые. Кроме того, порядок выполнения случайный.

Цикл for…in и объекты

Метод for…in предоставляет самый простой способ итерирования ключей и значений объекта, так как объекты не имеют доступа к методу forEach для массивов. Конечно есть методы Object.keys и Object.values которые дают ту же функциональность, но цикл for…of более гибок.

Цикл for…in и массивы

Для массивов ключом является индекс. Из этого следует что индексы — это перечисляемые свойства.

Пример for…in для массива

let users=['root','test']
for(let index in users){
console.log(`users[${index}]=${users[index]}`)
}
// result
users[0]=root
users[1]=test

Но все же, в большинстве случаев не рекомендуется использовать цикл for..in для работы с массивами, преимущественно из-за того, что порядок итерирования не гарантируется.

Использование for…in для строк

Каждый символ в строке имеет индекс. И подобно массивам, ети индексы являются перечисляемыми свойствами.
Пример for…in для строки

let str=['I love JavaScript']
for(let index in str){
  console.log(`${str[index]}`)
}
// result
I love JavaScript

Цикл for…of

Цикл for…of был добавлен в ES2015, для итерирования итерированных коллекций. То есть объектов что имеют свойство [Symbol.iterator].
Свойство [Symbol.iterator] позволяет нам обойти коллекцию вызывая функцию [Symbol.iterator]().next() для получения следующего элемента. Он применим к объектам классов Array, String, Map, Set, Uint8Array…

Пример for…of

let arr=['angular','typescript','react'];
const it = arr[Symbol.iterator]();
console.log(it.next().value)
console.log(it.next().value)
console.log(it.next().value)

// result
angular
typescript
react
undefined

for (const element of arr) {
    console.log(element);
}
// Result
angular
typescript
react
undefined

Цикл for…of проходит по элементах коллекции и присваивает их значение переменой element.

Также можно использовать ключевые слова break и continue.

for (const element of ['angular','typescript','react']) {
    if (x.length === 0) break;
    console.log(element);
}

Подводные камни for-of: он применим только к итерируемым объектам

Значение после of должно быть итерируемым. Что означает что нужно вручную переформатировать объект в массив чтобы получить его свойства.

const user = { email:'some@mail.com',login:'root' };

for (const prop of user) { // TypeError
    console.log(prop);
}

for (const prop of Array.from(user)) { // OK
    console.log(prop);
}

Итерирование с использованием деструкции

Использование for…of вместе с destructuring assingment особенно полезно для итерирования пар [ключ, значение].

const someMap = new Map();
someMap.set('key1', 10).set('key2', 20);
for (const [key,value] of someMap) {
  console.log(`key = ${key}, value = ${value}`);
}
// Result:
key = key1, value = 10
key = key2, value = 20

Array.prototype.entries() также возвращает итерируемые пары ключ значения

const array = ['angular','typescript','react'];
for (const [key,value] of arr.entries()) {
    console.log(`key = ${key}, value = ${value}`);
}
// Result:
key = 0, value = angular
key = 1, value = typescript
key = 2, value = react