Что с порядком 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 шт):
Берём таблицу приоритетов операторов и видим что 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
использует разность как аргумент. Разность должна быть вычислена первой. Аргументы разности вычисляются слева направо.