JavaScript. Подробное руководство, 6-е издание, стр. 154

<b>// Сконструировать конвейер генераторов для обработки текста.</b>

<b>// Сначала разбить текст на строки</b>

<b>let lines = eachline(text);</b>

<b>// Затем удалить начальные и конечные пробелы в каждой строке</b>

<b>let trimmed = map(lines, function(line) { return line.trim(); });</b>

<b>// Наконец, игнорировать пустые строки и комментарии</b>

<b>let nonblank = select(trimmed, function(line) {</b>

<b>  return line.length &gt; 0 &amp;&amp; 1ine[0] !=</b>

<b>});</b>

<b>// Теперь извлечь отфильтрованные строки из конвейера и обработать их,</b>

<b>// остановиться, если встретится строка “quit&quot;,</b>

<b>for (let line in nonblank) {</b>

<b>  if (line === &quot;quit&quot;) break; console.log(line);</b>

<b>}</b>

Обычно инициализация генераторов выполняется при их создании: аргументы, передаваемые функции-генератору, являются единственными значениями, которые принимают генераторы. Однако имеется возможность передать дополнительные данные уже работающему генератору. Каждый генератор имеет метод

<b>send(),</b>
который перезапускает генератор подобно методу
<b>next().</b>
Разница лишь в том, что методу
<b>send()</b>
можно передать значение, которое станет значением, возвращаемым выражением
<b>yield</b>
в функции-генераторе. (В большинстве генераторов, которые не принимают дополнительных входных данных, ключевое слово
<b>yield</b>
выглядит как инструкция. Однако в действительности
<b>yield</b>
- это выражение, возвращающее значение.) Кроме методов
<b>next()</b>
и
<b>send()</b>
существует еще один способ перезапустить генератор - метод
<b>throw().</b>
Если вызвать этот метод, выражение
<b>yield</b>
возбудит аргумент метода
<b>throw()</b>
как исключение, как показано в следующем примере:

<b>// Функция-генератор, ведущая счет от заданного начального значения.</b>

<b>// Метод send() позволяет увеличить счетчик на определенное значение.</b>

<b>// Вызов throw(&quot;reset&quot;) сбрасывает счетчик в начальное значение.</b>

<b>// Это всего лишь пример - здесь метод throw() используется не самым лучшим образом, </b>

<b>function counter(initial) {</b>

<b>  let nextValue = initial; // Сохранить начальное значение</b>

<b>  while(true) {</b>

<b>    try {</b>

<b>      let increment = yield nextValue; // Вернуть значение и получить приращение </b>

<b>      if (increment)                   // Если передано приращение...</b>

<b>        nextValue += increment;        // ...использовать его.</b>

<b>      else nextValue++;                 // Иначе увеличить на 1</b>

<b>    }</b>

<b>    catch (e) {                        // Если был вызван метод </b>

<b>      if (e===&quot;reset&quot;)  // throw() генератора</b>

<b>      nextValue = initial; else throw e;</b>

<b>    }</b>

<b>  }</b>

<b>}</b>

<b>let c = counter(10); // Создать генератор с начальным значением 10 </b>

<b>console.log(c.next()); //Выведет 10</b>

<b>console.log(c.send(2)); // Выведет 12</b>

<b>console.log(c.throw(&quot;reset&quot;)); // Выведет 10</b>

11.4.4. Генераторы массивов

Еще одна особенность, заимствованная в JavaScript 1.7 из языка Python, - генераторы массивов. Это механизм инициализации элементов массива на основе элементов другого массива или итерируемого объекта. Синтаксис генераторов массивов основан на математической форме записи элементов множества, т. е. выражения и инструкции находятся совсем не там, где привыкли их видеть программисты на языке JavaScript. Тем не менее привыкание к необычному синтаксису происходит достаточно быстро, а мощь генераторов массивов просто неоценима.

Ниже приводится пример генератора массивов, использующего созданную выше функцию range() для инициализации массива, содержащего квадраты четных чисел, меньшие 100:

<b>let evensquares = [х*х for (х in range(0,10)) if (х % 2 === 0)]</b>

Эта строка примерно эквивалентна следующим пяти строкам:

<b>let evensquares = [];</b>

<b>for(x in range(0,10)) {</b>

<b>  if (x % 2 === 0)</b>

<b>    evensquares.push(x*x);</b>

<b>}</b>

В общем случае синтаксис генераторов массивов имеет следующий вид:

<b>[ выражение for ( переменная in объект ) if ( условное выражение ) ]</b>

Обратите внимание на три основные части в квадратных скобках:

• Цикл

<b>for/in</b>
или
<b>for/each</b>
без тела. Эта часть генератора массивов включает переменную (или несколько переменных при использовании присваивания с разложением) слева от ключевого слова
<b>in</b>
и объект (который может быть генератором, итерируемым объектом или массивом) справа от ключевого слова
<b>in</b>
. Несмотря на отсутствие тела цикла, эта часть генератора массивов выполняет итерации и присваивает последовательные значения, определяемые переменной. Обратите внимание, что перед именем переменной не допускается указывать ключевое слово
<b>var</b>
или
<b>let</b>
- генераторы массивов неявно используют ключевое слово
<b>let</b>
, а используемая переменная недоступна за пределами квадратных скобок и не затирает существующую переменную с тем же именем.