чатfor of
Говоря оfor of
Поверьте, что все написалиJavaScript
люди использовалиfor of
, Для чего мы обычно его используем? В большинстве случаев это должен быть обход массива.Конечно, чаще мы также будем использоватьmap()
илиfiler()
для перебора массива. Но, как мы сказали в заголовке, это то же самое, что иGenerator
С чем это может быть связано?
Сначала мы думаем над вопросом, зачем использоватьfor of
илиmap()
/filer()
метод для перебора массива (или массивоподобного объекта:Strings
, Maps
, Sets
, arguments
) Шерстяная ткань? Почему их нельзя использовать для перебора объекта?
чему ты можешь научиться
- правильно
for of
более глубокое понимание -
iterator
Где свято? - Массивы тоже объекты, почему их нельзя использовать?
for of
перебирать объекты? - как реализовать объект
for of
? -
Generator
Где свято? Чем он хорош?
Тайна массивоподобных объектов
Прежде чем откроется настоящая тайна, встаньтеfor of
Подумайте об этом с точки зрения, теперь позвольте вам пройтись по массиву, какую информацию вам нужно знать?
- значение, соответствующее индексу
- завершать ли обход
Имея это в виду, давайте напечатаем массив, чтобы увидеть загадку:
const numbersArray = [1, 2, 3];
console.dir(numbersArray);
Массивы (или массивоподобные объекты:Strings
, Maps
, Sets
, arguments
) реализует метод в прототипеSymbol.iterator
, вопрос, то этоSymbol.iterator
Какая польза? Возьми и попробуй:
let iterator = numbersArray[Symbol.iterator]();
// 我们把这个 Symbol.iterator 打印一下看看里面到底有些什么
console.dir(iterator);
вот одинnext()
Это правильный путь? выполнить этоnext()
метод:
iterator.next(); // 输出 {value: 1, done: false}
iterator.next(); // 输出 {value: 2, done: false}
iterator.next(); // 输出 {value: 3, done: false}
iterator.next(); // 输出 {value: undefined, done: true}
Обратите внимание, что когда нижний индекс превышает значение: undefined
мы нашли этоiterator.next()
Каждый раз возвращается объект. Этот объект содержит две части информации: значение текущего индекса и флаг, указывающий, завершен ли обход. Это подтверждает то, что мы думали раньше, с этими двумя частями информации вы, какfor of
функция, также может распечатать каждый элемент массива, верно?
А вот и новый вопросiterator
Где свято?
iterator
(итератор) &The iterator protocol
(итеративный протокол)
болталиiterator
мы должны сказатьThe iterator protocol
(итеративный протокол)
Об этом говорится в MDN:The iterator protocol
разрешатьJavaScript
объектов, чтобы определить или настроить их поведение при итерации, поэтому приведенное вышеSymbol.iterator
Этот метод является реализацией массива для данного протокола. Итак, согласно этому протоколу, как массив реализуетiterator
Шерстяная ткань?
Этот большой раздел кажется трудоемким.Короче говоря, как мы подтвердили в предыдущей главе, способ его реализации заключается в определенииnext()
метод, и этоnext()
Метод возвращает объект каждый раз, когда он выполняется:{value:xxx/undefined , done: true/false }
вvalue
представляет текущее пройденное значение,done
Указывает, завершен ли обход.
Этот раздел отвечает на наш предыдущий вопрос: почему бы не использоватьfor of
перебирать объект? причина проста:JavaScript
Объект не реализует такойiterator
. Вы можете распечатать объект, чтобы посмотреть, что из этого выйдет:
console.dir({ a: 1, b: 2 });
ладно, если на этом заканчивается, значит, мы недостаточно понимаем, так что давайте зададим другой вопрос:
Почему нет встроенной итерации объекта? (почему вobject
Как насчет отсутствия встроенных итераторов?)
почему вobject
Как насчет отсутствия встроенных итераторов?
Да, почему? Нам также нужно обойти объект в различных сценариях? Почему нет встроенного итератора? Чтобы ответить на этот вопрос, мы должны взглянуть на некоторые основные понятия с другой точки зрения:
Мы часто говорим об обходе объектов, но, говоря простым языком, есть только два уровня для работы с одним.JavaScript
Объект для обхода:
-
Иерархия программ - что это значит? На уровне программы, когда мы перебираем объект, мы перебираем свойства объекта, отображающие его структуру. Это может быть неправильно понято, например:
Array.prototype.length
Это свойство связано со структурой объекта, но не с его данными. -
Иерархия данных - означает повторение структуры данных и извлечение ее данных. Например: когда мы перебираем массив, итератор перебирает все его данные, если
array = [a, b, c, d]
Затем итератор получает доступ1, 2, 3, 4
.
понять причину,JavaScript
Хотя не поддерживаетсяfor of
перебирать объекты, но предоставлятьfor in
метод для перебора всех не-Symbol
type и является перечислимым свойством.
Стандарт не поддерживает, если мы будем использоватьfor-of
перебирать объекты? Тогда мы можем произвольно реализовать один:
Object.prototype[Symbol.iterator] = function*() {
for (const [key, value] of Object.entries(this)) {
yield { key, value };
}
};
for (const { key, value } of { a: 1, b: 2, c: 3 }) {
console.log(key, value);
}
Не знаю, обратили ли вы внимание на какую-то деталь в нашем сознательном осуществленииiterator
В коде мы используем очень странную структуруfunction*() {}
, это то, что мы представим дальшеGenerator
Generators
Когда я вижу это имя, я думаю, что оно потрясающее, но на самом деле оно очень простое, просто напишитеGenerator
Вам просто нужно добавить имя функции иfunction
Добавьте ключевое слово в середине*
номера достаточно. Что касается внутриyield
Что это такое, мы поговорим об этом позже.
talk is cheap , show me the code
, На примере кратко расскажу о концепции.
Теперь мы определим такойGenerator
называетсяgen
function* gen() {
yield 1;
yield 2;
yield 3;
yield 4;
}
Мы видим только, что в нем 4 утверждения, поэтому распечатайте его и посмотрите:
Знакомая функция была найдена здесь,next()
метод, мы ставимgen
создать его, выполнить егоnext()
Посмотрим на результат:
Это все еще знакомый вкус, так что здесь мы уже знаем,Generator
может создать экземплярiterator
, и этоyield
Операторы используются для прерывания выполнения кода, то есть для взаимодействия сnext()
метод, который будет выполняться только по одномуyield
утверждение.
Еще одно слово дляGenerator
Сама по себе есть интересная особенность,yield
может следовать за другимGenerator
и они будут выполняться в порядке:
function* gen() {
yield 1;
yield* gen2();
return;
}
function* gen2() {
yield 4;
yield 5;
}
let iterator = gen();
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
Результаты интересные, не так ли? а такжеreturn
закончится весьGenerator
, другими словами: напишите вreturn
Назадyield
не будет выполняться.
Генератор для чего?
Generator
В чем польза?Умные студенты могли догадаться, да, это может прерывать функцию выполнения кода, что может помочь нам контролировать порядок выполнения асинхронного кода:
Например, есть две асинхронные функцииA
а такжеB
, а такжеB
ПараметрыA
возвращаемое значение , то есть, еслиA
Выполнение не заканчивается, мы не можем выполнитьB
.
Затем пишем псевдокод:
function* effect() {
const { param } = yield A();
const { result } = yield B(param);
console.table(result);
}
В это время, если нам нужно получитьresult
Тогда нам нужно:
const iterator = effect()
iterator.next()
iterator.next()
сделать это дваждыnext()
Получите результат, выглядит глупо, не так ли? Есть ли хороший способ? (ерунда, должно быть)
Предположим, вы бежитеA()
/ B()
После завершения запроса он будет выполнен автоматическиnext()
метод? Разве это не решает?
Такая библиотека уже существовала, и вам рекомендуется обратиться к нейco
Конечно, вы также можете прочитать исходный кодэта статьяПриходите посмотреть, в конце концовGenerator
как играть.
наконец
буклетХитрости отладки Chrome, о которых вы не зналиПредпродажа стартовала.
Добро пожаловать в публичный аккаунт "Front-end Bully", отсканируйте код, чтобы следовать, вас ждет много хорошего~