Что с порядком yield у генераторов JS?

Решил поэкспериментировать с генераторами в javascript, и обнаружил странное (для меня) поведение. Порядок исполнения yield лично мне не совсем понятен.

Возьмём вот такой код:

function* gen() {
   return yield yield 5;
}
const iter = gen();
console.log(iter.next()); // value = 5
console.log(iter.next(2)); // value = 2
console.log(iter.next(3)); // value = 3

В принципе логично, что сначала исполняется самый правый yield и они идут словно порядок у стека.

Но возьмём к примеру следующий код:

function* gen() {
  return (yield) + (yield) - (yield);
}
const iter = gen();
console.log(iter.next()); // value = undefined
console.log(iter.next(2)); // value = undefined
console.log(iter.next(4)); // value = undefined
console.log(iter.next(7)); // value = -1
// Вот как получилось -1: 2 + 4 - 7 = -1

Добавление скобок и операторов делает почему-то порядок последовательным.

И вот следующий пример:

function* gen() {
  return yield (yield) - (yield);
}
const iter = gen();
console.log(iter.next()); // value = undefined,
console.log(iter.next(3)); // value = undefined,
console.log(iter.next(6)); // value = -3,
console.log(iter.next(7)); // value = 7,
// Вот как получилось -3: 3 - 6 = -3
// А 7 просто подставилось

А вот в этом примере порядок срабатывания yield следующий 2,3,1.

Почему порядок именно такой, описан ли он где-то в документации или стандартe? Если не описан, то интересно почитать ваше мнение по какому принципу идёт срабатывание yield


Ответы (1 шт):

Автор решения: Stanislav Volodarskiy

Берём таблицу приоритетов операторов и видим что yield или унарный оператор или вовсе не имеет операнда. Приоритет у него один из самых низких, ниже только оператор "запятая".

1

//                 1
//              -------
   return yield yield 5;
//        -------------
//              2

yield yield 5 компилируется в yield (yield 5). Левый yield использует выражение в скобках, которое должно быть вычислено первым. Порядок справа налево.

2

//          1         2         3
//       -------   -------   -------
  return (yield) + (yield) - (yield);

(yield) + (yield) - (yield) чуть хитрее. Скобки вокруг yield делают его оператором без аргумента, что можно представить как (yield undefined) + (yield undefined) - (yield undefined). Цепочка из плюсов и минусов вычисляется слева направо. То есть, yield будут вызваны слева направо.

3

//                1         2
//             -------   -------
  return yield (yield) - (yield);
//       -----------------------
//                  3

yield (yield) - (yield) компилируется в yield ((yield) - (yield)), у yield приоритет ниже чем у -. Самый левый yield использует разность как аргумент. Разность должна быть вычислена первой. Аргументы разности вычисляются слева направо.

→ Ссылка