ru:https://highload.today/blogs/mozhno-vse-i-po-svoim-pravilam-kak-rabotaet-iteratsiya-v-javascript/ ua:https://highload.today/uk/blogs/mozhna-vse-i-za-svoyimi-pravilami-yak-pratsyuye-iteratsiya-v-javascript/
logo
Back-end      11/08/2022

Можно все, и по своим правилам: как работает итерация в JavaScript

Владислав Хирса BLOG

Senior Backend Developer | Node.js | NestJS | Express.js | SQL | NoSQL | AWS

Привет всем. Меня зовут Владислав Хирса, я — Software Engineer в Grid Dynamics. В этой статье я расскажу вам много полезного об итерации в JavaScript.

Мы все используем итерацию для перебора массивов и объектов разных размеров и разных задач. Но знаем ли мы, как это работает? Как мы можем изменить поведение итерации над нашими данными и в каких случаях это может потребоваться?

Если вам интересны ответы на эти вопросы, то этот материал точно для вас.

Вспомним термины

Для лучшего понимания вспомним несколько значений, а именно:

  • Перечисляемые свойства enumerable properties — одно из трех свойств (configurable, enumerable, writable), имеющихся в объекте. Относительно enumerable, то она отвечает за то, можно ли вернуть свойство в цикле for...in.

Например, так:

Object.prototype.getType = function() {
  return this.type;
};
const object = {
  language: 'JavaScript',
  type: 'Lesson'
};
for (const key in object) {
  console.log(key); // JavaScript, Lesson, getType;
};
  • Итерированный объект и terable object — это объект, построенный по определенному паттерну и имеющий типичное итерационное поведение. Он итерируется с помощью spread syntax [...], for...of и for await...of. И в этой статье мы поговорим именно о нем.
  • Протокол итерации iterator protocol это протокол, с помощью которого мы можем создать собственные правила, по которым будет итерироваться наш объект. Если подробнее, то итерировать мы сможем такие типы данных, как string, array, object.

Главные правила iterator protocol это:

  1. У нас должен быть метод next().
  2. Курс DevOps engineer.
    Стань DevOps інженером і відповідай за автоматизацію процесів розробки, тестування та випуску продукту. .
    Реєстрація на курс
  3. Метод next() должен обязательно возвращать объект типа iterable object. Он содержит ключи value, которые могут иметь любое значение, и done, который может быть true или false.
  4. Когда итерация завершилась, нужно обязательно вернуть объект { done: true }, ведь только после этого наша итерация закончится.
  5. Если done не будет возвращен или done будет иметь какое-либо негативное значение, такое как undefined, null и другие, то наша итерация будет бесконечной.

Создание итеративного поведения

Для создания итеративного поведения мы будем использовать следующие подходы:

  • Symbol.iterator с методом next();
  • Symbol.iterator с генератором;
  • Symbol.asyncIterator с генератором.

Так что по порядку, и начнем мы с Symbol.iterator с методом next().

var array = [10, 20, 30, 40, 50];
array[Symbol.iterator] = function () {
  let i = 0;
  return {
    next() {
      i++
      return (i <= 5)
        ? { value: i, done }
        : { done: true }
    }
  }
};
for (const el of array) {
  console.log(el) // 1, 2, 3, 4, 5
};

Как это работает?

Сначала цикл for...of ищет в нашем объекте или среди тех, от которых он наследуется в prototype, есть ли у него Symbol.iterator. Если нет — то будет вызвана автоматическая ошибка, а если да — тогда он вызывает функцию, функция возвращает наш объект с методом next(), где и есть вся наша основная логика, и самое главное, что при каждой итерации цикла используется метод next(), который и возвращает значение по нашим условиям.

Symbol.iterator з генератором

С Symbol.iterator уже ознакомились, а как насчет генераторов?

Генератор, если коротко, то это способ создания того же iterable object для итерации по iterator protocol, то есть у него тоже есть метод next() и он итерируется циклом for...of, только синтаксис другой, и использовать его в некоторых случаях удобнее:

var it = {};
it[Symbol.iterator] = function* () {
  yield 1;
  yield 2;
  yield 3;
};
it.type = 'Lesson';
console.log(it); // { type: "Lesson", Symbol(Symbol.iterator): * Symbol.iterator() }
console.log([...it]); // [1, 2, 3]

В этой части мы изменили поведение объекта и дали ему возможность быть итерированным. Без Symbol.iterator была бы ошибка такого типа — Uncaught TypeError: it is not iterable при попытке итерировать объект. Так же как мы видим, что к итерационным данным мы не имеем доступа напрямую, а с Symbol.iterator нет доступа к значениям объекта. Это очень удобно, и нет никаких мутаций данных.

Symbol.asyncIterator з генератором

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

Файл async-iterator.ts:

import { AsyncLimitIteratorParametersType } from './types';
export default class Iterator {
  public static generateAsyncLimitIterator(
    data: AsyncLimitIteratorParametersType
  ) {
    const {
      from,
      to,
      limit,
      asyncFunction,
      asyncFunctionParams
   } = data;
    return {
      async *[Symbol.asyncIterator]() {
        for (let now = from; now < to; now += limit) {
          yield await asyncFunction(
            asyncFunctionParams,
            { from, to, limit, now }
          );
        }
      }
    }
  }
};

Файл types.d.ts:

export type AsyncLimitIteratorParametersType = {
  from: number;
  to: number;
  limit: number;
  asyncFunction: Function;
  asyncFunctionParams: any;
}
export type IterationDataType = {
  from: number;
  to: number;
  limit: number;
  now: number;
};

Класс Iterator создан для асинхронной обработки (изменения) больших массивов данных.

Так что разберем, как его можно использовать и в чем его преимущества.

Класс Iterator

Итак, класс Iterator. У него есть один статический метод generateAsyncLimitIterator, к которому мы имеем доступ, не используя оператор new, метод generateAsyncLimitIterator принимает параметры:

  • from — из какого индекса изменять массив;
  • Курс Python Pro.
    Опануй розробку на основі фреймворків та навички роботи з базами даних, навчися працювати з супутніми технологіями GIT та Linux, отримай навички роботи з мовою Python.
    Дійзнайтеся більше
  • to — по какой позиции по индексу изменять массив;
  • limit — сколько элементов за одну итерацию захватить и пройти;
  • asyncFunction — функция, в которой выполняются основные действия.

Например, запрос на базу данных для изменения объекта пользователей. asyncFunctionParams параметры, принимаемые функцией asyncFunction.

Пример применения:

const iteratorParams = {
  from: 0,
  to: 1000,
  limit: 10,
  asyncFunction: changeUsers,
  asyncFunctionParams: params
};
const iterateObj = Iterator.generateAsyncLimitIterator(iteratorParams);
for await (let value of iterateObj) {
  //
}

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


На этом все! Надеюсь, что было полезно. Желаю успехов и продуктивного кодинга 😉

If you have found a spelling error, please, notify us by selecting that text and pressing Ctrl+Enter.

Курс Frontend.
Frontend розробник може легко створити сторінки вебсайту чи вебдодаток. Тому після курсу ви станете затребуваним фахівцем у сфері, що розвивається.
Інформація про курс

Этот материал – не редакционный, это – личное мнение его автора. Редакция может не разделять это мнение.

Топ-5 самых популярных блогеров февраля

Всего просмотровВсего просмотров
181
#1
Всего просмотровВсего просмотров
181
Senior Project Manager at Nemesis
Всего просмотровВсего просмотров
92
#2
Всего просмотровВсего просмотров
92
Software Architect at Devlify
Всего просмотровВсего просмотров
88
#3
Всего просмотровВсего просмотров
88
Всего просмотровВсего просмотров
68
#4
Всего просмотровВсего просмотров
68
Android Team Lead у Balancуй Team
Всего просмотровВсего просмотров
46
#5
Всего просмотровВсего просмотров
46
Рейтинг блогеров

Ваша жалоба отправлена модератору

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам: