Автор оригинала: FreeCodeCamp Community Member.
Часть 2 нашей серии обсуждает протоколы итерации, для петлей и функций генератора
Это часть 2 мастерства JavaScript – и, вероятно, самые захватывающие части языка. (До тех пор, пока часть 3 приходит, во всяком случае;))
Часть 1 покрыла языковые основы И здесь мы будем покрывать итерационные протокола (ы), их использование для петлей и функции генератора.
Почему генератор функционирует в смеси? Если вы думаете, что это случайное дополнение, читайте! Генераторы связаны с итерацией!
Для петлей
Ну, вы знаете базовый для цикла, верно?
для (пусть; i Вы бы использовали это для доступа к элементам в массиве. Вы бы использовали что-то подобное для доступа к свойствам/значениям объекта: для (пусть; i И снова, что-то подобное для Поскольку должен быть один лучший способ сделать вещи, здесь у нас есть Ну да. Они оба являются петлями, чтобы повторить что-то, но вот где сходство заканчивается, как мы увидим ниже. Давайте начнем с попыток повторить ценности в объекте. Для доступа к элементам в массиве: Для доступа к значению объекта: Красиво, не так ли? Это порождает вопрос, однако, почему нет Давайте погрузиться глубже в то, как это работает и где все можно использовать Добро пожаловать в мир Во-первых, краткое замечание о протоколах. Если вы имели дело с Ооп Раньше, тогда вы, вероятно, знаете, какой интерфейс: это описание действий, которые можно сделать объект, как договор. Если вы хотите сделать У нас есть 2 протокола итерации в JavaScript: Этот протокол позволяет объектам JS определить их итерационное поведение. Это включает в себя объект, который будет передан. Это также определяет, что именно итерации. Интерфейс требует метода [Symboly.iterator) где-то до цепь прототипа. Этот протокол определяет, как наш потенциальный протокол должен возвращать итоцируемые значения. Эх? Примером сделает этот яснее. То, как мне нравится видеть, протокол итератора определяет интерфейс класса для итератора. (Если вы снова посмотрите на имя, это казалось бы довольно очевидным, да? Итератор Интерфейс. Смотри, я могу js сейчас.) Возвращаясь к нашей дорогой документации: Итак, наш интерфейс итератор полностью определяется существованием Один ключевой момент, чтобы сделать здесь, это считается наилучшей практикой для реализации как итераторов, так и итеративных протоколов, поскольку некоторые функции/синтаксис могут ожидать прежнего, а некоторые последние. Это позволяет использовать оба с вашим итератором. Вот замечательный пример: Красота лежит в Помните оператор распространения? – Это также принимает итеративный протокол! И, конечно же, работает с Под капотом мы можем теперь понять, что происходит: все эти методы используют Обязательно облегчает вещи, когда вам не нужно делать это самостоятельно. Там один бит, мы не трогали, что идет рука об руку с На простом взгляде разница кажется очевидной: Существует перечислимый дескриптор свойств над свойствами. Это определяет, перечисляется ли данное свойство, настраиваемо или запись. Конечно, это все еще не там. Возвращаясь к вопросу, которое заставило нас пойти вниз по этой кроличной дыре – почему нет Почему нет? Простой ответ – это выбор языкового дизайна. Почему они выбрали это? Потому что многие объекты наследуют от базового объекта. Наличие итогеруемого протокола на базовом объекте будет означать, что все эти объекты являются утеряемыми. Например: ваши объекты даты становятся итеративными, что не имеет никакого смысла. Это приводит нас к последнему виду для циклов: Foreach Coop. Я видел, как люди запутались, почему нет Простой ответ – Чтобы закончить раздел петель, одна общая банка. При использовании объектов в JS в качестве карт (или словари, HASHMAP) вы можете столкнуться с проблемами, когда какой-то ключ совпадает с свойством цепочки прототипа. Рассмотрим этот пример: У вас есть объект с определенными ключами, которые вы хотите включить. Вы, наверное, просто хотел увидеть Таким образом, два правила, чтобы избежать этой проблемы: Если вы переопределили Помните Функции генератора Разрешить ввод на запросы и выйти из функции. Точки входа и выхода исправлены. Это как многократная входная виза. Они очень мощные инструменты, чтобы получить сложные вещи. То, как я думаю о функциях генератора, так это: они полезны для создания списка значений на лету без накладных расходов наличия массива. Почему бы не просто проиграть на массиве ценностей? Ну, генераторы экономиют пространство. Не существует массива, чтобы начать с – просто вычисление (или ввод/вывод), необходимо получить следующий элемент из «массива». Давайте погрузимся в механику этого. Вызов генераторной функции не выполняет тело, но возвращает объект итератора для функции. Тело выполняется, когда вы называете итератор Это Давайте сделаем эту концепцию бетон с примером. Давайте сделаем Tweet Trial из части 1. Хорошо, здесь многое здесь. Давайте сломаемся. Во-первых, у нас есть генератор функции, который генерирует твиты на основе UserID и количество твитов для генерации. Эта функция вернет бы объект итератора. Таким образом, вот что Подвески означает, что генератор еще не закрыт/закончен. Итак, существуют ценности, которые он может обеспечить. Мы можем получить доступ к этому через На оборотной стороне Это именно поэтому мы можем сделать На данный момент генератор закончен. У нас здесь Таким образом, когда мы регистрируем следующее значение в следующей строке, мы получаем Это все для примера. Но эта история не заканчивается здесь. Вы можете получить генераторы, а также генераторы! Вы делаете это через Генераторы могут также Ну, это поступило достаточно долго, я думаю, что спаснул другие прохладные биты для следующих частей. Забавный факт? Мы вообще избавимся от петель. Добро пожаловать в мир карты, фильтр и уменьшить. Читать больше сообщений моего блога на neilkakkar.com Отказкарта
, Установить
И любой другой пользовательский объект, который вы определяете. Когда вы хотите только значения/свойства, написание этого цикла, может привести к ошибкам. Вы можете использовать неверное свойство длины, вы можете сделать одно ошибки, или вы можете подумать Object.Keys (OBJ). Длина
просто просто уродливая (я делаю).для ... из
и для ... в
Петли! … Один лучший, верно?Для … цикла
для (пусть ценность ARR)
для (пусть var of tobile.values (obj))
для (пусть var obj)
Просто работать?для ... из
петля. Самое главное, как ваши классы/объекты используют это.Итерация
протоколы.Х
, вам нужно иметь функцию, определенную в договоре, который делает X. Например, dox (a, b, c)
который принимает параметры A, B, C. Таким же образом протоколы являются интерфейсами в JavaScript.Передача протокола
Итераторский протокол
Далее ()
функция на объекте.const iteratorObject = {
next() {
const value = Math.random();
if ( value < this.threshold ) {
return { done: false, value};
}
return { done: true};
},
[Symbol.iterator]: function() {
return this;
},
threshold: 0.7
}
[Символ .-ТРЕТИКА]
часть итератора. Определив это, мы позволяем нашему итератору подвергаться воздействию различных функций и синтаксисов, которые нуждается в итеративный протокол, а не только протокол итератор. Что вы можете сделать с этим?>[...iteratorObject]
[0.03085962239970308, 0.20649861146804716]
для ... из
, где началась эта история.>for (let val of iteratorObject) {
console.log(val);
}
0.6234680935767514
0.525812241023621
[Символ .-ТРЕТИКА]
генерировать итератор и итерацию над тем, что использует Следующий
!>const iter = iteratorObject[Symbol.iterator]()
undefined
>iter.next();
{done: false, value: 0.04474940944875905}
>iter.next();
{done: true}
для ... из
петли, которые есть: для ... в
Отказ Какая разница? Давайте погрузимся, начиная с нашего примера!Для … в петлях
>for (const val in iteratorObject) {
console.log(val);
}
next
threshold
для ... в
Получает свойства, пока для ... из
Получает значения! Почему [Symboly.iterator] отсутствует тогда? Ну, есть 2 причины.> Object.getOwnPropertyDescriptors(iteratorObject)
{ next:
{ value: [Function: next],
writable: true,
enumerable: true,
configurable: true },
threshold:
{ value: 0.7,
writable: true,
enumerable: true,
configurable: true },
[Symbol(Symbol.iterator)]:
{ value: [Function: [Symbol.iterator]],
writable: true,
enumerable: true,
configurable: true } }
для ... в
Цветные петли по свойствам, перечислимый дескриптор которого устанавливается на true, а также не символьные свойства. Это объясняет это, верно? Просто для подтверждения, вы можете добавить новое свойство на объект, с перечисляемым настроен на false, и он не будет отображаться в для ... в
петля.Object.defineProperty(iteratorObject, "newHiddenProperty", {
enumerable: false,
value: "hidden",
})
Object.keys ()
использует той же методологию.>for(const val in iteratorObject) {
console.log(val);
}
next
threshold
для (пусть Val Obj)
Просто работать? Теперь вы знаете, верно? Поскольку не существует неотъемлемого протокола по прототипу объекта!Foreache Lop.
foreach
Работайте везде (как на объектах), и я отвечу этот вопрос здесь.Array.prototype.foreach ()
Отказforeach
Цикл определяется только для массивов! Итак, вы можете использовать их только с массивами. Теперь foreach
не заботится, откуда приходит этот массив. Это может быть простой родной массив или массив, генерируемый объектами, как object.keys ().const baseObject = {
a: 1,
b: 2,
someProperty: function() {
return 4;
}
}
const myObjectMap = Object.create(baseObject);
myObjectMap.c = 3; // key set in map for some reason.
for(let val in myObjectMap) { // this iterates up the chain!
console.log(val);
}
> c
a
b
someProperty
C
ключ, который вы установили. Вы можете исправить это через:for (let val in myObjectMap) {
if (myObjectMap.hasOwnProperty(val)) {
console.log(val);
}
}
> c
HasownProperty ()
Чтобы проверить, вы ищете ключ, существуют в объекте (а не в цепочке проторовки)HasownProperty
как ключ в ваших словарях/карты.HasownProperty
, еще есть способ использовать его, поскольку это метод прототипа объекта.myObjectMap.hasOwnProperty = 4;
for(let val in myObjectMap) {
if (myObjectMap.hasOwnProperty(val)) {
console.log(val);
}
}
> Uncaught TypeError: myObjectMap.hasOwnProperty is not a function
at
Позвоните
и Применить
от последней части? Это один удивительный способ использовать их.Функции генератора
Далее ()
метод. Как насчет фиксированной точки выхода? Все тело не выполнено, а только до следующего доходность
выражение в организме.доходность
Выражение также указывает значение, которое нужно возвращено.function * generateTweets(userID, numberOfTweets) {
for(let i=0; i< numberOfTweets; i++) {
const tweet = randomTweetGenerator(); // assume this gives you a string of words < 280 characters.
yield { tweet, userID, tweetID: i};
}
}
const tweetList = generateTweets('neilkakkar', 3);
for( let tweet of tweetList) {
console.log(tweet);
}
> {tweet: "hi", userID: "neilkakkar", tweetID: 0}
{tweet: "how's it going?", userID: "neilkakkar", tweetID: 1}
{tweet: "I'm automagic", userID: "neilkakkar", tweetID: 2}
console.log(tweetList.next());
> {value: undefined, done: true}
TweetList
является.> tweetList
generateTweets {
TweetList.next ()
– Что даст нам объект с двумя ключами, ценность
и сделано
Отказдля ... из
Петли понять протокол итерации, чтобы они могли соблюдать весь генератор самостоятельно!для ... из
на TweetList
и получить наши твиты.для ... из
петля потребляет все значения.> tweetList
generateTweets {
сделано: правда
Как мы ожидаем – и никаких ценностей.Урожай *
Отказfunction * generateTweetsForSomeUsers(users, numberOfTweets) {
for(let user of users) {
yield * generateTweets(user, numberOfTweets)
}
}
Возвращение
вместо доходность
Отказ Это приводит к тому, что генератор закончен.