Заповнення генераторів

Non-standard
This feature is non-standard and is not on a standards track. Do not use it on production sites facing the Web: it will not work for every user. There may also be large incompatibilities between implementations and the behavior may change in the future.

Obsolete since Gecko 58 (Firefox 58 / Thunderbird 58 / SeaMonkey 2.55)
This feature is obsolete. Although it may still work in some browsers, its use is discouraged since it could be removed at any time. Try to avoid using it.

Нестандартний. Не використовуйте!
Синтаксис заповнень генераторів є нестандартним та був прибраний, починаючи з Firefox 58. Для використання в майбутньому розгляньте генератори.

Синтаксис заповнення генераторів (generator comprehension) був виразом JavaScript, який дозволяв швидко збирати нову функцію-генератор, базуючись на вже існуючому ітерабельному об'єкті. Однак, він був прибраний зі стандарту та з реалізації Firefox. Не використовуйте його!

Синтаксис

(for (x of iterable) x)
(for (x of iterable) if (condition) x)
(for (x of iterable) for (y of iterable) x + y)

Опис

У заповненнях генераторів дозволені наступні два види компонентів:

Перебір for-of завжди є першим компонентом. Можна використовувати більше одного перебору for-of чи if-конструкцій.

Значним недоліком заповнень масивів є те, що вони можуть спричинити конструювання у пам'яті цілого нового масиву. Коли самі вхідні дані для заповнення є маленьким масивом, затрати пам'яті є незначними — але коли вхідні дані є великим масивом, або затратним (чи взагалі нескінченним) генератором, створення нового масиву може бути проблематичним.

Генератори дозволяють ліниві обчислення послідовностей, з обчисленням елементів на вимогу, коли є потреба. Заповнення генераторів синтаксично майже ідентичні заповненням масивів — вони використовують круглі дужки замість квадратних — але замість створення масиву вони створюють генератор, який може виконуватися ліниво. Можете вважати їх скороченим синтаксисом для створення генераторів.

Припустимо, ми маємо ітератор it, який перебирає великі послідовності цілих чисел. Ми бажаємо створити новий ітератор, який перебиратиме їхні подвоєні значення. Заповнення масиву створило б цілий масив у пам'яті, що містив би подвоєні значення:

var doubles = [for (i in it) i * 2];

Заповнення генератора, з іншого боку, створило б новий ітератор, який створював би подвоєні значення на вимогу, в разі потреби:

var it2 = (for (i in it) i * 2);
console.log(it2.next()); // Перше значення з it, подвоєне
console.log(it2.next()); // Друге значення з it, подвоєне

Коли заповнення генератора використовується як аргумент функції, круглі дужки, що використовуються для виклику функції, означають, що зовнішні дужки можна пропустити:

var result = doSomething(for (i in it) i * 2);

Значною відмінністю між цими двома прикладами є те, що, використовуючи заповнення генератора, ви перебиратимете структуру 'obj' лише один раз, всього, на відміну від одного обходу при заповненні масиву та ще одного під час його перебору.

Приклади

Прості заповнення генераторів

(for (i of [1, 2, 3]) i * i );
// функція-генератор, що видає 1, 4 та 9

[...(for (i of [1, 2, 3]) i * i )];
// [1, 4, 9]

var abc = ['А', 'Б', 'В'];
(for (letters of abc) letters.toLowerCase());
// функція-генератор, що видає "а", "б" та "в"

Заповнення генераторів з оператором if

var years = [1954, 1974, 1990, 2006, 2010, 2014];

(for (year of years) if (year > 2000) year);
// функція-генератор, що видає 2006, 2010 та 2014

(for (year of years) if (year > 2000) if (year < 2010) year);
// функція-генератор, що видає 2006, те саме нижче:

(for (year of years) if (year > 2000 && year < 2010) year);
// функція-генератор, що видає 2006

Заповнення генераторів у порівнянні з функцією-генератором

Легко зрозуміти синтаксис заповнення генераторів, порівнявши його з функцією-генератором.

Приклад 1: Простий генератор.

var numbers = [1, 2, 3];

// Функція-генератор
(function*() {
  for (let i of numbers) {
    yield i * i;
  }
})();

// Заповнення генератора
(for (i of numbers) i * i );

// Результат: Обидва повертають генератор, який видає [1, 4, 9]

Приклад 2: Використання if у генераторі.

var numbers = [1, 2, 3];

// Функція-генератор
(function*() {
  for (let i of numbers) {
    if (i < 3) {
      yield i * 1;
    }
  }
})();

// Заповнення генератора
(for (i of numbers) if (i < 3) i);

// Результат: обидва вертають генератор, який видає [1, 2]

Специфікації

Заповнення генераторів було початково присутнє у чорнетці ECMAScript 2015, але було прибране у ревізії 27 (серпень 2014). Будь-ласка, дивіться семантику специфікації у старших ревізіях ES2015.

Сумісність з веб-переглядачами

No compatibility data found. Please contribute data for "javascript.operators.generator_comprehensions" (depth: 1) to the MDN compatibility data repository.

Відмінності від заповнень у JS1.7/JS1.8

Заповнення JS1.7/JS1.8 були прибрані з Gecko 46 (bug 1220564).

Старий синтаксис заповнень (більше не використовується!):

(X for (Y in Z))
(X for each (Y in Z))
(X for (Y of Z))

Відмінності:

  • Заповнення ES7 створюють область видимості для кожного блоку "for", а не для всього заповнення.
    • Старе: [...(()=>x for (x of [0, 1, 2]))][1]() // 2
    • Нове: [...(for (x of [0, 1, 2]) ()=>x)][1]() // 1, кожна ітерація створює свіже зв'язування для x.
  • Заповнення ES7 починаються з "for", а не з виразу присвоювання.
    • Старе: (i * 2 for (i of numbers))
    • Нове: (for (i of numbers) i * 2)
  • Заповнення ES7 можуть мати декілька компонентів if та for.
  • Заповнення ES7 працюють тільки з переборами for...of, а не з for...in.

Див. також