Итераторы

Многие встроенные классы поддерживают перебор с помощью итераторов. Благодаря этому, например, мы можем перебрать массив с помощью цикла for...of:

const process = require('process');
let arr = [1, 2, 3];
for (let value of arr) {
   process.stdout.write(`${value} `);
} // 1 2 3

Или преобразовать строку в массив букв с помощью оператора SPREAD:

let str = 'string';
let arr = [...str];
console.log(arr);    // [ 's', 't', 'r', 'i', 'n', 'g' ]

Объект, поддерживающий итерации, возвращают также функции-генераторы:

function* gen() {
   yield 10;
   yield 20;
   yield 30;
}
let arr = [...gen()];
console.log(arr);    // [ 10, 20, 30 ]
let it = gen();
console.log(it);     // Object [Generator] {}

Итератор содержит метод next(), с помощью которого можно перейти к следующему значению. Объект, возвращаемый методом next(), имеет два свойства: value (позволяет получить текущее значение) и done (содержит значение true, если больше нет значений, и false — в противном случае):

let map = new Map();
map.set('a', 1).set('b', 2);
let it = map.keys();
console.log( it );        // [Map Iterator] { 'a', 'b' }
console.log( it.next() ); // { value: 'a', done: false }
console.log( it.next() ); // { value: 'b', done: false }
console.log( it.next() ); // { value: undefined, done: true }
it = map.keys();
console.log( it.next().value ); // a
console.log( it.next().value ); // b

Создать итератор можно также с помощью символа Symbol.iterator:

let map = new Map();
map.set('a', 1).set('b', 2);
let it = map[Symbol.iterator]();
console.log( it );        // [Map Entries] { [ 'a', 1 ], [ 'b', 2 ] }
console.log( it.next() ); // { value: [ 'a', 1 ], done: false }
console.log( it.next() ); // { value: [ 'b', 2 ], done: false }
console.log( it.next() ); // { value: undefined, done: true }

Свойство с названием Symbol.iterator должно содержать ссылку на функцию, которая возвращает объект, поддерживающий итерации:

let obj = {};
obj[Symbol.iterator] =  function*() {
   yield 10;
   yield 20;
};
console.log( [...obj] ); // [ 10, 20 ]

Цикл for...of сначала как раз и вызывает метод с названием Symbol.iterator, а затем работает с возвращаемым им объектом, содержащим метод next(). В предыдущем разделе мы создали массивоподобный объект, который не поддерживает итерации. Давайте сделаем этот объект итерируемым (листинг 11.15).

Листинг 11.15. Итерируемые массивоподобные объекты

let obj = {
   0: 20,
   1: 30,
   2: 40,
   length: 3,
   [Symbol.iterator]: function() {
      return {
         _index: 0,
         _arr: this,
         next() {
            if (this._index < this._arr.length) {
               return {
                  done: false,
                  value: this._arr[this._index++]
               };
            }
            else {
               return { done: true, value: undefined };
            }
         },
         toString() {
            return 'MyIterator {}';
         }
      };
   }
};
console.log( [...obj] ); // [ 20, 30, 40 ]
let it = obj[Symbol.iterator]();
console.log( it.toString() ); // MyIterator {}
console.log( it.next() );     // { done: false, value: 20 }
console.log( it.next() );     // { done: false, value: 30 }
console.log( it.next() );     // { done: false, value: 40 }
console.log( it.next() );     // { done: true, value: undefined }
for (let value of obj) {
   console.log(value);
}

Учебник по Node.js и JavaScript
Учебник по JavaScript (Node.js) в формате PDF

Помощь сайту

ЮMoney (Yandex-деньги): 410011140483022

ПАО Сбербанк:
Счет: 40817810855006152256
Реквизиты банка:
Наименование: СЕВЕРО-ЗАПАДНЫЙ БАНК ПАО СБЕРБАНК
Корреспондентский счет: 30101810500000000653
БИК: 044030653
КПП: 784243001
ОКПО: 09171401
ОКОНХ: 96130
Скриншот реквизитов