Символы JavaScript, итераторы, генераторы, асинхронные/ожидания и асинхронные итераторы – все объясняется просто

1656620811 simvoly javascript iteratory generatory asinhronnyeozhidaniya i asinhronnye iteratory – vse

Содержание статьи

от rajaraodv

cTE7Bo-3Q9T-WyuFOMTkr1LmR1vkwRvoGsSB

Некоторые функции JavaScript (ECMAScript) легче понять, чем другие. Generators выглядят странно – как указатели в C/C++. Symbols удается смотреться одновременно и примитивами, и объектами.

Все эти функции взаимосвязаны и опираются друг на друга. Поэтому вы не можете понять одно, не понимая другого.

Поэтому в этой статье я расскажу symbols,global symbols,iterators, iterables, generators , async/await и async iterators. я объясню»почему” они там в первую очередь, а также показывают, как они работают на некоторых полезных примерах.

Это относительно продвинутый предмет, но это не ракетостроение. Эта статья должна дать вам очень хорошее представление обо всех этих понятиях.

Хорошо, начнем.?

HBiVhsE9-rPJxFPNFdN5-5ZnnZSQmzN89X7H

символы

В ES2015 новый (6-й) тип данных называется symbol было создано.

ПОЧЕМУ?

Три основные причины были:

Причина №1 — Добавьте новые основные функции с обратной совместимостью

Разработчикам JavaScript и комитета ECMAScript (TC39) потребовался способ добавлять новые свойства объекта, не нарушая существующие методы, например for in циклы или методы JavaScript, напримерObject.keys.

Например, если у меня есть объект, var myObject = {firstName:'raja', lastName:'rao'} и если я бегуObject.keys(myObject) оно бы вернулось[firstName, lastName] .

Теперь, если мы добавим другое свойство, скажем newProperty к myObject а если вы бежите Object.keys(myObject) это след до сих пор возвращать старые значения (т.е. каким-то образом заставить его игнорировать только что добавленные newproperty), и показать просто[firstName, lastName] — и нет [firstName, lastName, newProperty] . Как это сделать?

Мы не могли сделать это раньше, поэтому вызван новый тип данных Symbols было создано.

Если добавить newProperty то как символ Object.keys(myObject) игнорировать это (поскольку он об этом не знает) и все равно возвращается [firstName, lastName] !

Причина №2 — избегайте коллизий имен

Они тоже хотели сохранить эти свойства уникальными. Таким образом, они могут продолжать добавлять новые свойства (и вы можете добавлять свойства объекта) в глобальные, не беспокоясь о коллизии имен.

Например, скажем, что у вас есть объект, к которому вы добавляете пользовательский toUpperCase к глобальному Array.prototype .

Теперь представьте, что вы скачали другую библиотеку (или вышел ES2019), и у нее была другая версия Array.prototype.toUpperCase. Тогда ваша функция может сломаться из-за столкновения имен.

J6B2ibbhbGxk4KQq4j4CYL6zVTWXyXL6-B4o

Как решить эту коллизию имен, о которой вы, возможно, не знаете? Вот где Symbols Они внутренне создают уникальные значения, позволяющие создавать свойства сложения, не беспокоясь о конфликте имен.

Причина №3 – включить крючки для основных методов с помощью «известных» символов

Предположим, вам нужна какая-нибудь основная функция, скажемString.prototype.search чтобы вызвать пользовательскую функцию. Это, ‘somestring’.search(myObject); следует позвонить myObject’s функция поиска и пас ‘somestring’ как параметр! Как мы это делаем?

Именно здесь ES2015 придумал кучу глобальных символов, называемых «известными» символами. И пока ваш Объект имеет один из этих символов как свойство, вы можете перенаправить основные функции для вызова вашей функции!

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

Создание символов

Вы можете создать символ, вызвав вызванную глобальную функцию/объект Symbol . Эта функция возвращает значение типа данных symbol.

clCoLqejtYU7HEECtCfze7I8Al5voKei--8-

Примечание: Символы могут выглядеть как объекты, поскольку у них есть методы, но это не так — они примитивны. Вы можете думать о них как о «специальных» объектах, которые имеют определенное сходство с обычными объектами, но не ведут себя как обычные объекты.

Например: символы имеют методы так же, как и объекты, но в отличие от объектов они неизменны и уникальны.

Символы не могут быть созданы с помощью ключевого слова «new».

Потому что символы – это не объекты, а new ключевое слово должно возвращать объект, который мы не можем использовать new вернуть а symbols тип данных.

var mySymbol = new Symbol(); //throws error

Символы имеют «описание»

Символы могут быть описаны только для ведения журнала.

//mySymbol variable now holds a "symbol" unique value//its description is "some text"const mySymbol = Symbol('some text');

Символы уникальны

const mySymbol1 = Symbol('some text');const mySymbol2 = Symbol('some text');mySymbol1 == mySymbol2 // false

Символы ведут себя как синглтон, если мы используем метод «Symbol.for».

Вместо создания a symbol через Symbol() вы можете создать его с помощью Symbol.for(<key>). Для создания символа требуется «ключ» (строка). А если символ с that key уже существует, он просто возвращает старый символ! Поэтому он ведет себя как одиночный, если мы мыe the Symbол.для метода.

var mySymbol1 = Symbol.for('some key'); //creates a new symbolvar mySymbol2 = Symbol.for('some key'); // **returns the same symbolmySymbol1 == mySymbol2 //true 

Истинная причина использовать .for состоит в том, чтобы создать символ в одном месте и получить доступ к тому же символу из другого места.

Внимание: Symbol.for сделает символ неуникальным в том смысле, что вы переопределите значение, если ключи одинаковые! Поэтому старайтесь избегать этого, если это возможно!

«Описание» символа против «ключа»

Просто чтобы было понятнее, если вы не используете Symbol.for , то Символы уникальны. Однако если вы его используете, то если ваш key не уникальным, то возвращенные символы также не будут уникальными.

8zbLMllXK82Hk5TjWO0xZgSm8gWlTIp6QAKu

Символы могут быть ключом свойства объекта

Это очень уникальная вещь по отношению к символам — и также самая запутанная. Хотя они смотрятся как объект, они просты. И мы можем присоединить символ к объекту как ключ свойства, так и строку.

На самом деле это один из основных способов использования символов — как свойств объекта!

R-dqw1eSSUtKqHL4rqpLOlPDtjTtpclIHSty

Примечание: Свойства объекта, являющиеся символами, известны как «свойства ключей».

Оператор скобок против оператора точки

Вы не можете использовать оператор точки, поскольку операторы точки работают только со свойствами строки, поэтому вам следует использовать оператор скобок.

hfq5DSd88rGXqlUpyqsJn258KvQu3CD-LniM

3 основные причины использовать Symbols — обзор

Давайте еще раз рассмотрим три основные причины, когда мы знаем, как работают символы.

Причина №1 – символы невидимые для циклов и других методов

Цикл for-in в примере ниже выполняет цикл над объектом obj но он не знает (или игнорирует)prop3 и prop4 потому что они символы.

FO2t8FHLz9eRviM4xBs8wLk4SOxR1u7ne31x

Ниже приведен еще один пример где Object.keys и Object.getOwnPropertyNames игнорируют имена свойств, являющихся символами.

OpEPnJHKdDXt3332AS27me9YBMr3Tx6Efyj-

Причина №2 — Символы уникальные.

Предположим, вам нужна функция под названием Array.prototype.includes на глобальном Array объект. Он столкнется со значением по умолчанию includes метод, который JavaScript (ES2018) поставляется из готовой коробки. Как добавить его без столкновений?

Сначала создайте переменную с собственным названием includes и назначить ему символ. Затем добавьте эту переменную (теперь символ) к глобальной Array используя обозначения в скобках. Назначьте любую функцию.

Наконец, вызовите эту функцию, используя обозначения в скобках. Но обратите внимание, что вы должны передать фактический символ в скобках, например: arr[includes]() а не как строчка.

lJo8y-zLg8TZtPXBfyVEmtJSJ3yb6gR7GFoO

Причина №3. Хорошо известные символы (т.е. «глобальные» символы)

По умолчанию JavaScript автоматически создает кучу переменных символов и назначает их глобальным Symbol объект (да, то же Symbol()мы используем для создания символов).

В ECMAScript 2015 эти символы затем добавляются к основным методам, таким как String.prototype.search и String.prototype.replace основных объектов, таких как массивы и строчки.

Некоторые примеры этих символов: Symbol.match, Symbol.replace, Symbol.search, Symbol.iterator и Symbol.split.

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

Например, объект String String.prototype.search public метод ищет регулярное выражение или строку и возвращает индекс, если найден.

69xn6K7tJAA6eJeKkEi8n-bRebGfM7fphoRf

В ES2015 он сначала проверяет, Symbol.search метод реализован в запросе regExp (объект RegExp). Если да, то он вызывает эту функцию и делегирует ей работу. Основные же объекты, такие как RegExp, реализуют Symbol.search символ, действительно выполняющий работу.

Внутренняя работа Symbol.search (ПОВЕДЕНИЕ ПО Умолчанию)

  1. Разбор ‘rajarao’.search(‘rao’);
  2. Превратите «rajarao» в объект String new String(“rajarao”)
  3. Превратите «rao» в объект RegExp new Regexp(“rao”)
  4. Звоните search метод строчного объекта «rajarao».
  5. search внутренние вызовы метода Symbol.search метод на объект «rao» (делегирует поиск обратно объекту «rao») и передает «rajarao». Что-то вроде этого: "rao"[Symbol.search]("rajarao")
  6. "rao"[Symbol.search]("rajarao") возвращает результат индекса как 4к search функция и, наконец, search возвращается 4 вернуться к нашему коду.

Фрагмент псевдокода ниже показывает, как работает код внутри:

eRX3vzKog8jhzxjyMoOMxEyq4-OxrmrxPcYq

Но приманкой является то, что вам больше не нужно проходить RegExp. Вы можете передать любой пользовательский объект, реализующий Symbol.search и верните все, что хотите, и это продолжит работать.

Давайте посмотрим.

Настройка метода String.search для вызова нашей функции

Нижеследующий пример показывает, как мы можем сделать String.prototype.search позвоните нашим Product функция поиска класса — благодаря Symbol.search глобальный Symbol.

kcc8eq6pH5DRkxRTMDTIkCPJpnr4zgrWVESY

Внутренняя работа: Symbol.search (CUSTOM BEHAVIOR)

  1. Разбор ‘barsoap’.search(soapObj);
  2. Превратите “barsoap” в объект String new String(“barsoap”)
  3. Так как soapObj уже является объектом, не выполняйте никаких преобразований
  4. Звоните search метод «barsoap» String объект.
  5. search внутренние вызовы метода Symbol.search метод на «soapObj” (т.е. он делегирует поиск обратно к “soapObj” объект) и передайте «мыло». Что-то вроде этого: soapObj[Symbol.search]("barsoap")
  6. soapObj[Symbol.search]("barsoap") возвращает результат индекса как FOUND к search функция и, наконец, search возвращается FOUND вернуться к нашему коду.

Надеюсь, теперь вы хорошо понимаете символы.

Ладно, перейдем к итераторам.

kEHK8PEgmOHaS6VUgG23msLpi8X8sMxPQsbV

Итераторы и итераторы

ПОЧЕМУ?

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

Но дело в том, что у нас уже есть стандартные методы, такие как for-of оператор цикла и распространение () для извлечения коллекций данных из стандартных объектов, таких как массивы, строки и карты. Почему мы не можем использовать эти стандартные методы для нашего Object?

В следующем примере мы не можем использовать цикл for-of или оператор распространения для извлечения данных из нашего Users класс. Мы должны использовать обычай get метод.

0ZUUfwRblzYmzhfuh9ziyANRNRgzNefSRVQA

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

Если они соблюдают эти правила для извлечения данных из своих объектов, то такие объекты называются «итеративными».

Правила следующие:

  1. Основной объект/класс должен хранить некоторые данные.
  2. Основной объект/класс должен иметь глобальный «известный» символ symbol.iterator как его свойство, реализующее конкретный метод согласно правилам №3-6.
  3. Это symbol.iterator метод должен возвращать другой объект – объект «итератор».
  4. Этот объект «итератор» должен иметь метод, который называется next метод.
  5. The next метод должен иметь доступ к данным, хранящимся в правиле №1.
  6. А если позвоним iteratorObj.next()он должен возвращать некоторые сохраненные данные из правила №1 или как {value:<stored data>, done: false}, если он хочет вернуть больше значений, or as {done: true}, если он больше не хочет возвращать данные.

Если все эти 6 правил соблюдены, то главный объект называется «итерационный” из правила №1. Объект, который он вернул, называется «итератор”.

Давайте посмотрим, как мы можем сделать наш Users объект и итерация:

NCcsb6xvxscZ24U7swkutqwjjFfi4YYHECd-
Нажмите для увеличения

Важное примечание: Если мы пройдем мимо iterable (allUsers) for-of оператор цикла или распространение, внутрь они вызывают <iterable>[Symbol.iterator](), чтобы получить итератор (like allUsersIterator), а затем используйте итератор для извлечения данных.

Таким образом, все эти правила существуют для того, чтобы иметь стандартный способ возврата iterator объект.

mPZxgsP8mMLNhJIqiXGF5yFPJ5fdmeJk9dyG

Функции генератора

ПОЧЕМУ?

Есть две основные причины:

  1. обеспечить абстракцию высшего уровня для итераторов
  2. Предоставьте новый контрольный поток, чтобы помочь с такими вещами, как «ад обратного звонка».

Рассмотрим их подробно.

ПРИЧИНА №1 — Обертка для итераторов

Вместо того чтобы сделать наш класс/объект an iterable соблюдая все эти правила, мы можем просто создать нечто, называемое методом «Генератор», чтобы упростить вещи.

Ниже приведены некоторые из основных моментов о генераторах:

  1. Методы генератора имеют новый *<myGeneratили> синтаксис внутри класса, а функции Generator имеют syntax function * myGeneratили(){}.
  2. Вызов генераторов myGenerator()возвращает а generator объект, который также реализует iterator протокол (правила), поэтому мы можем использовать это как iterator вернуть значение из коробки.
  3. Генераторы используют спец yield оператор для возврата данных.
  4. yield операторы отслеживают предварительные вызовы и просто продолжают с того места, где остановились.
  5. Если вы используете yield внутри цикла он будет выполняться только один раз каждый раз, когда мы вызываем next() метод на итераторе

Пример 1:

Код ниже показывает, как вы можете использовать метод генератора (*getIterator()) вместо использования Symbol.iterator метод и реализация next метод, отвечающий всем правилам.

pZfUjKv5veWYeQQ1zskNUzsL-mEJZ1cGrnko
Использование генераторов внутри класса

Пример 2:

Вы можете упростить это еще больше. Сделайте функцию генератором (с синтаксисом*) и используйте yield чтобы возвращать значение по одному, как показано ниже.

nYHrw83GR5EF0jPwR3p-0bbkwmBXJuQJB8ER
Использование генераторов непосредственно в качестве функций

Важное примечание: Хотя в приведенных выше примерах я использую слово «итератор» для представления allUsers это действительно a generator объект.

Объект генератора имеет такие методы, как throw и return в дополнение к next метод! Но для практических целей мы можем использовать возвращенный объект как просто «итератор».

ПРИЧИНА №2 — Обеспечьте лучшие и новые потоки управления

Помогите предоставить новые потоки управления, которые помогают нам писать программы по-новому и решать такие вещи, как «ад обратного вызова».

Заметьте, в отличие от обычной функции, функция генератора может yield (сохранять функции state и return значение), а также быть готовым принять дополнительные входные значения в точке, где она уступила.

На рисунке ниже каждый раз видит yield, он может возвращать значение. Вы можете использовать generator.next(“some new value”) и передать новое значение в точку, где она была получена.

y3hrnT63qXkWewIj4rWbfocef-Mu8TeY02gi
Нормальная функция против функции генератора

Нижеследующий пример более конкретно показывает, как работает поток управления:

JlyaniqPAd5mszB37kq3YbGhELKpdbsTm11c
Поток управления генератором

Синтаксис и использование генератора

Функции генератора можно использовать следующими способами:

xNnkTFsqv23fBgya2lKmTyUb-COXeU4SCVIj

Мы можем иметь больше кода после yield (в отличие от оператора return)

Так же, как и return ключевое слово, yield ключевое слово также возвращает значение, но это позволяет нам иметь код после выдачи!

w9dKtBLs7v3t5sLre8jpFmQ3TCgEWLTN99uj

Вы можете получить несколько урожаев

RtoVwrmiWrKVGZOnXX5MEqedj2IqllxMmeZW
вы можете иметь несколько операторов yield

Отправка значений назад и вперед к генераторам с помощью метода «следующий».

Итераторы next метод также может передавать значение обратно в генератор, как показано ниже.

Фактически, эта функция позволяет генераторам устранить «ад обратного вызова». Немного вы узнаете об этом больше.

Эта функция также используется в библиотеках, таких как redux-saga.

В следующем примере мы вызываем итератор с пустым next() звоните, чтобы получить вопросы. А потом мы проходим 23 как значение, когда мы называем next(23) 2-й раз.

aSFH1y8bOkNPhzJgN4KFZH3g5QGTxwGIifIs
Передача значения назад к генератору извне через «Next»

Генераторы помогают устранить «ад обратного звонка»

Вы знаете, что мы попадаем в ад обратных вызовов, если есть несколько асинхронных вызовов.

Нижеприведенный пример показывает, как библиотеки, такие как «co», используют функцию генератора, которая позволяет нам передавать значения через файл. next метод, который поможет нам писать асинхронный код синхронно.

Обратите внимание, как co функция передает результат с обещания обратно в генератор через next(result) на Шагах №5 и Шагах №10.

DJH7bZWmgDAmQMiecWmHXsPjKN9aiIzC0BGB
Пошаговое объяснение библиотек, таких как «co», использующих «next(

Ладно, перейдем к асинхронному/ожиданию.

q2ozY1fqYuvuRBnzmJZSxRDH4e1FTUhF254H

ASYNC/AWAIT

ПОЧЕМУ?

Как вы видели ранее, генераторы могут помочь устранить «ад обратного вызова», но вам нужна сторонняя библиотека, например co чтобы это произошло. Но «ад обратного звонка» — это такая большая проблема, что комитет ECMAScript решил создать обертку только для этого аспекта Generator и вышел с новыми ключевыми словами async/await.

Различия между Generators и Async/Await:

  1. async/await использует await вместо yield.
  2. await работает только с Promises.
  3. Вместо этого function*он использует async function ключевое слово.

Поэтому async/await по существу является поднабором генераторов и имеет новый синтаксический сахар.

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

В следующем примере getAmount функция вызывает две асинхронные функции getUser и getBankBalance . Мы можем сделать это в обещание, но используя async await более элегантный и простой.

3vUZj-y4RZb-LV2gDU2jNeL7n02zjUH9zbos
m9Ky899WlWX2Soj6vEleyTNOHt0LGVSEcZF7

Асинкетные итераторы

ПОЧЕМУ?

Это довольно распространённый сценарий, когда нам нужно вызвать асинхронные функции в цикле. Поэтому в ES2018 (завершено предложение) комитет TC39 разработал новый символ Symbol.asyncIterator а также новая конструкция for-await-of чтобы помочь нам легко перебирать асинхронные функции.

Основное отличие обычных итераторов от асинхронных итераторов состоит в следующем:

Объект итератора

  1. Объект итератора next() метод возвращает значение как {value: ‘some val’, done: false}
  2. Использование: iterator.next() //{value: ‘some val’, done: false}

Объект асинхронного итератора

  1. Метод next() объекта асинхронного итератора возвращает Promise что впоследствии превращается в нечто подобное {value: ‘some val’, done: false}
  2. Использование: iterator.next().then(({ value, done })=> {//{value: ‘some val’, done: false}}

Нижеследующий пример показывает, как for-await-of работает и как вы можете им воспользоваться.

vgX-wE-V4P3j1f6v6qQv4FERtQXZYAR7-9PC
ожидание (ES2018)

РЕЗЮМЕ

символы — предоставить глобально уникальный тип данных. Вы используете их в основном как свойства объекта для добавления новых способов поведения, чтобы не нарушать стандартные методы, например Object.keys и for-in петли.

Известные символы — это автоматически созданные символы JavaScript и могут использоваться для реализации основных методов в наших пользовательских объектах

Итерации — это любые объекты, которые хранят коллекцию данных и соблюдают определенные правила, чтобы мы могли использовать стандартные for-of петля и ... операторы распространения для извлечения данных из них.

Итераторы — возвращаются Iterables и имеют next метод — это то, что действительно извлекает данные из файла iterable.

Генераторы -обеспечить абстракцию высшего уровня для Iterables. Они также обеспечивают новые потоки управления, которые могут решать такие вещи, как ад обратного вызова, и обеспечивают строительные блоки для таких вещей, как Async/Await.

Async/Await — обеспечивает абстракцию более высокого уровня для генераторов, чтобы решить проблему обратного вызова.

Асинхронные итераторы — совершенно новая функция 2018 года, которая помогает перебирать массив асинхронных функций для получения результата каждой асинхронной функции, как в обычном цикле.

Это почти все!

Дальнейшее чтение

ECMAScript 2015+

  1. Вот примеры всего нового в ECMAScript 2016, 2017 и 2018
  2. Просмотрите эти полезные советы и рекомендации по ECMAScript 2015 (ES6).
  3. 5 «плохих» частей JavaScript, исправленных в ES6
  4. Является ли «Класс» в ES6 новой «плохой» частью?

Другие мои сообщения можно найти здесь.

Если это было полезно, щелкните, пожалуйста, мальчик? нажмите кнопку внизу несколько раз, чтобы показать поддержку! ⬇⬇⬇

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *