Итерируемым (перечисляемым) считается любой объект, который реализует символьное свойство Symbol.iterator. Ряд встроенных в JavaScript типов, таких как Array, String, Map, Set, уже имеют свойство Symbol.iterator и реализуют его, таким образом являясь итерируемыми.
Если у объектов такого типа вызвать функцию Symbol.iterator, то вернется функционал (функция next()), позволяющий перебирать данный объект в цикле. В ответе же на вызов функции next() должен возвращаться объект с двумя свойствами:
done- булево значение, показывающее, закончен ли перебор;value- значение следующего итерируемого элемента.
Пример:
let list = [1, 2, 3];
let listIterator = list[Symbol.iterator]();
console.log(listIterator.next().value); // 1
console.log(listIterator.next().done); // false
console.log(listIterator.next().value); // 3
console.log(listIterator.next().done); // true
Таким образом, можно создавать свои итерируемые объекты и самим реализовывать какой-то свой кастомный перебор таких объектов.
Цикл for..of
Производит перебор элементов итерируемого объекта с использованием функции Symbol.iterator:
let list = [3, 4, 5];
for (let val of list) {
console.log(val); // 3, 4, 5
}
Отличие for..of от for..in
for..in возвращает список ключей итерируемого объекта, тогда как for..of возвращает список значений его свойств:
let list = [3, 4, 5];
for (let i in list) {
console.log(i); // 0, 1, 2
}
for (let i of list) {
console.log(i); // 3, 4, 5
}
Транспилированный код
Если компилятор TypeScript настроен на соответствие требованиям ES3 или ES5, то цикл for..of будет преобразован в следующий код:
for (var _i = 0, list_1 = list; _i < list_1.length; _i++) {
var i = list_1[_i];
console.log(i); // 3, 4, 5
}
При этом, если попытаться использовать цикл for..of на объектах, тип которых отличен от Array, даже если эти объекты реализуют Symbol.iterator, TypeScript сообщит об ошибке.