ÐвиÑÐ°Ð¹Ð½Ñ ÑÑнкÑÑÑ Ð¿Ð¾Ð²ÐµÑÑаÑÑÑ Ð»Ð¸Ñе одне, Ñдине знаÑÐµÐ½Ð½Ñ (або нÑÑого).
ÐенеÑаÑоÑи можÑÑÑ Ð¿Ð¾Ð²ÐµÑÑаÑи (âyieldâ) кÑлÑка знаÑенÑ, одне за одним, на вимогÑ. Ðони ÑÑдово пÑаÑÑÑÑÑ Ð· обâÑкÑами, Ñо пеÑебиÑаÑÑÑÑÑ, дозволÑÑÑи легко ÑÑвоÑÑваÑи поÑоки Ð´Ð°Ð½Ð¸Ñ .
ФÑнкÑÑÑ-генеÑаÑоÑи
Щоб ÑÑвоÑиÑи генеÑаÑоÑ, нам поÑÑÑбна ÑпеÑÑалÑна ÑинÑакÑиÑна конÑÑÑÑкÑÑÑ: function*, Ñак звана âÑÑнкÑÑÑ-генеÑаÑоÑâ.
Це виглÑÐ´Ð°Ñ Ð¾ÑÑ Ñак:
function* generateSequence() {
yield 1;
yield 2;
return 3;
}
ФÑнкÑÑÑ-генеÑаÑоÑи поводÑÑÑÑÑ ÑнакÑе, нÑж звиÑайнÑ. Ðоли Ñака ÑÑнкÑÑÑ Ð²Ð¸ÐºÐ»Ð¸ÐºÐ°ÑÑÑÑÑ, вона не запÑÑÐºÐ°Ñ ÑвÑй код. ÐамÑÑÑÑ ÑÑого вона повеÑÑÐ°Ñ ÑпеÑÑалÑний обâÑкÑ, Ñкий називаÑÑÑÑÑ Â«Ð¾Ð±âÑкÑ-генеÑаÑоÑ», Ñоб кеÑÑваÑи ÑÑ Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñм.
ÐÑÑ Ð¿Ð¾Ð´Ð¸Ð²ÑÑÑÑÑ:
function* generateSequence() {
yield 1;
yield 2;
return 3;
}
// "ÑÑнкÑÑÑ-генеÑаÑоÑ" ÑÑвоÑÑÑ "обâÑкÑ-генеÑаÑоÑ"
let generator = generateSequence();
alert(generator); // [object Generator]
ÐÐ¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ ÐºÐ¾Ð´Ñ ÑÑнкÑÑÑ Ñе не ÑозпоÑаÑо:
ÐÑновним меÑодом генеÑаÑоÑа Ñ next(). ÐÑи Ð²Ð¸ÐºÐ»Ð¸ÐºÑ Ð²Ñн запÑÑÐºÐ°Ñ Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ ÐºÐ¾Ð´Ñ Ð´Ð¾ найближÑого опеÑаÑоÑа yield <value> (value можна опÑÑÑиÑи, ÑÐ¾Ð´Ñ Ð²Ð¾Ð½Ð¾ Ñ undefined). ÐоÑÑм Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ ÑÑнкÑÑÑ Ð¿ÑизÑпинÑÑÑÑÑÑ, а оÑÑимане value повеÑÑаÑÑÑÑÑ Ð´Ð¾ зовнÑÑнÑого кодÑ.
РезÑлÑÑаÑом next() завжди Ñ Ð¾Ð±âÑÐºÑ Ð· двома влаÑÑивоÑÑÑми:
value: оÑÑимане знаÑеннÑ.done:true, ÑкÑо код ÑÑнкÑÑÑ Ð·Ð°ÐºÑнÑивÑÑ, ÑнакÑеfalse.
ÐапÑиклад, ÑÑÑ Ð¼Ð¸ ÑÑвоÑÑÑмо генеÑаÑÐ¾Ñ Ñ Ð¾ÑÑимÑÑмо його пеÑÑе знаÑеннÑ, Ñо повеÑÑаÑÑÑÑÑ:
function* generateSequence() {
yield 1;
yield 2;
return 3;
}
let generator = generateSequence();
let one = generator.next();
alert(JSON.stringify(one)); // {value: 1, done: false}
Ðа даний Ð¼Ð¾Ð¼ÐµÐ½Ñ Ð¼Ð¸ оÑÑимали лиÑе пеÑÑе знаÑеннÑ, а Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ ÑÑнкÑÑÑ Ð²ÑдбÑваÑÑÑÑÑ Ð½Ð° дÑÑÐ³Ð¾Ð¼Ñ ÑÑдкÑ:
ÐавайÑе Ð·Ð½Ð¾Ð²Ñ Ð²Ð¸ÐºÐ»Ð¸Ñемо generator.next(). ÐÑн вÑдновлÑÑ Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ ÐºÐ¾Ð´Ñ Ñ Ð¿Ð¾Ð²ÐµÑÑÐ°Ñ Ð½Ð°ÑÑÑпний yield:
let two = generator.next();
alert(JSON.stringify(two)); // {value: 2, done: false}
Ð ÑкÑо ми викликаÑмо його вÑÑеÑÑ, Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ Ð´Ð¾ÑÑÐ³Ð°Ñ Ð¾Ð¿ÐµÑаÑоÑа return, Ñкий завеÑÑÑÑ Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ ÑÑнкÑÑÑ:
let three = generator.next();
alert(JSON.stringify(three)); // {value: 3, done: true}
Ð¢ÐµÐ¿ÐµÑ Ð³ÐµÐ½ÐµÑаÑÐ¾Ñ Ð²Ð¸ÐºÐ¾Ð½Ð°Ð²ÑÑ. Ðи можемо побаÑиÑи Ñе за Ð´Ð¾Ð¿Ð¾Ð¼Ð¾Ð³Ð¾Ñ done:true Ñ Ð¾Ð±ÑобиÑи value:3 Ñк кÑнÑевий ÑезÑлÑÑаÑ.
ÐÐ¾Ð²Ñ Ð²Ð¸ÐºÐ»Ð¸ÐºÐ¸ generator.next() бÑлÑÑе не маÑÑÑ ÑенÑÑ. ЯкÑо ми ÑÑ
Ñобимо, вони повеÑÑаÑÑÑ Ñой Ñамий обâÑкÑ: {done: true}.
function* f(â¦) Ñи function *f(â¦)?Ðбидва ÑинÑакÑиÑи пÑавилÑнÑ.
Ðле зазвиÑай пеÑевага вÑддаÑÑÑÑÑ Ð¿ÐµÑÑÐ¾Ð¼Ñ ÑинÑакÑиÑÑ, оÑкÑлÑки зÑÑоÑка * ознаÑаÑ, Ñо Ñе ÑÑнкÑÑÑ-генеÑаÑоÑ, вона опиÑÑÑ Ð²Ð¸Ð´, а не ÑмâÑ, ÑÐ¾Ð¼Ñ ÑÑ ÑлÑд ÑозÑаÑовÑваÑи Ñазом Ñз клÑÑовим Ñловом function.
ÐеÑебÑÑ Ð³ÐµÐ½ÐµÑаÑоÑÑв
Як ви, напевно, вже здогадалиÑÑ, дивлÑÑиÑÑ Ð½Ð° меÑод next(), генеÑаÑоÑи Ñ Ð¾Ð±âÑкÑами, Ñо пеÑебиÑаÑÑÑÑÑ.
Ðи можемо пеÑебиÑаÑи ÑÑ
знаÑÐµÐ½Ð½Ñ Ð·Ð° Ð´Ð¾Ð¿Ð¾Ð¼Ð¾Ð³Ð¾Ñ for..of:
function* generateSequence() {
yield 1;
yield 2;
return 3;
}
let generator = generateSequence();
for(let value of generator) {
alert(value); // 1, поÑÑм 2
}
ÐиглÑÐ´Ð°Ñ Ð½Ð°Ð±Ð°Ð³Ð°Ñо пÑиÑмнÑÑе, нÑж виклик .next().value, Ñи не Ñак?
â¦Ðле звеÑнÑÑÑ ÑвагÑ: Ñ Ð¿ÑÐ¸ÐºÐ»Ð°Ð´Ñ Ð²Ð¸Ñе показано 1, поÑÑм 2, Ñ Ñе вÑе. ÐнаÑÐµÐ½Ð½Ñ 3 не показÑÑÑÑÑÑ!
Це ÑомÑ, Ñо пеÑебÑÑ ÑеÑез for..of ÑгноÑÑÑ Ð¾ÑÑÐ°Ð½Ð½Ñ value, коли done: true. ÐÑже, ÑкÑо ми Ñ
оÑемо, Ñоб ÑÑÑ ÑезÑлÑÑаÑи вÑдобÑажалиÑÑ ÑеÑез for..of, Ñо Ð¿Ð¾Ð²Ð¸Ð½Ð½Ñ Ð¿Ð¾Ð²ÐµÑÑаÑи ÑÑ
ÑеÑез yield:
function* generateSequence() {
yield 1;
yield 2;
yield 3;
}
let generator = generateSequence();
for(let value of generator) {
alert(value); // 1, поÑÑм 2, поÑÑм 3
}
ÐÑкÑлÑки генеÑаÑоÑи Ñ Ð¾Ð±âÑкÑами, Ñо пеÑебиÑаÑÑÑÑÑ, ми можемо викоÑиÑÑовÑваÑи вÑÑ Ð¿Ð¾Ð²âÑÐ·Ð°Ð½Ñ Ð· ними ÑÑнкÑÑоналÑнÑÑÑÑ, напÑиклад ÑинÑакÑÐ¸Ñ ÑозÑиÑÐµÐ½Ð½Ñ ...:
function* generateSequence() {
yield 1;
yield 2;
yield 3;
}
let sequence = [0, ...generateSequence()];
alert(sequence); // 0, 1, 2, 3
У Ð½Ð°Ð²ÐµÐ´ÐµÐ½Ð¾Ð¼Ñ Ð²Ð¸Ñе ÐºÐ¾Ð´Ñ ...generateSequence() пеÑеÑвоÑÑÑ Ð¾Ð±âÑкÑ-генеÑаÑоÑ, Ñо пеÑебиÑаÑÑÑÑÑ, в маÑив елеменÑÑв (докладнÑÑе пÑо ÑинÑакÑÐ¸Ñ ÑозÑиÑÐµÐ½Ð½Ñ ÑиÑайÑе Ñ Ð³Ð»Ð°Ð²Ñ ÐалиÑÐºÐ¾Ð²Ñ Ð¿Ð°ÑамеÑÑи Ñа ÑинÑакÑÐ¸Ñ Ð¿Ð¾ÑиÑеннÑ)
ÐикоÑиÑÑÐ°Ð½Ð½Ñ Ð³ÐµÐ½ÐµÑаÑоÑÑв Ð´Ð»Ñ Ð¾Ð±âÑкÑÑв, Ñо пеÑебиÑаÑÑÑÑÑ
ÐеÑкий ÑÐ°Ñ ÑÐ¾Ð¼Ñ Ð² Ð³Ð»Ð°Ð²Ñ ÐÑеÑаÑÐ¸Ð²Ð½Ñ Ð¾Ð±âÑкÑи ми ÑÑвоÑили обâÑÐºÑ range, Ñо пеÑебиÑаÑÑÑÑÑ Ñа повеÑÑÐ°Ñ Ð·Ð½Ð°ÑÐµÐ½Ð½Ñ from..to.
ÐÑÑ, давайÑе згадаÑмо код:
let range = {
from: 1,
to: 5,
// for..of range Ð²Ð¸ÐºÐ»Ð¸ÐºÐ°Ñ Ñей меÑод один Ñаз на ÑÐ°Ð¼Ð¾Ð¼Ñ Ð¿Ð¾ÑаÑкÑ
[Symbol.iterator]() {
// ...вÑн повеÑÑÐ°Ñ Ð¾Ð±âÑкÑ, Ñо пеÑебиÑаÑÑÑÑÑ:
// Ð´Ð°Ð»Ñ for..of пÑаÑÑÑ Ð»Ð¸Ñе з Ñим обâÑкÑом, запиÑÑÑÑи в нÑого наÑÑÑÐ¿Ð½Ñ Ð·Ð½Ð°ÑеннÑ
return {
current: this.from,
last: this.to,
// next() викликаÑÑÑÑÑ Ð¿Ñи кожнÑй ÑÑеÑаÑÑÑ Ñикла for..of
next() {
// повинно повеÑнÑÑи знаÑÐµÐ½Ð½Ñ Ñк обâÑÐºÑ {done:.., value :...}
if (this.current <= this.last) {
return { done: false, value: this.current++ };
} else {
return { done: true };
}
}
};
}
};
// пÑи пеÑебоÑÑ Ð¾Ð±âÑкÑа range повеÑÑаÑÑÑÑÑ ÑиÑла вÑд range.from до range.to
alert([...range]); // 1,2,3,4,5
Ðи можемо викоÑиÑÑовÑваÑи ÑÑнкÑÑÑ-генеÑаÑÐ¾Ñ Ð´Ð»Ñ Ð¿ÐµÑебоÑÑ Ð¾Ð±âÑкÑа, вказавÑи ÑÑ Ñк Symbol.iterator.
ÐÑÑ Ñой Ñамий range, але набагаÑо компакÑнÑÑий:
let range = {
from: 1,
to: 5,
*[Symbol.iterator]() { // ÑкоÑоÑÐµÐ½Ð½Ñ Ð´Ð»Ñ [Symbol.iterator]: function*()
for(let value = this.from; value <= this.to; value++) {
yield value;
}
}
};
alert( [...range] ); // 1,2,3,4,5
Це пÑаÑÑÑ, ÑÐ¾Ð¼Ñ Ñо range[Symbol.iterator]() ÑÐµÐ¿ÐµÑ Ð¿Ð¾Ð²ÐµÑÑÐ°Ñ Ð³ÐµÐ½ÐµÑаÑоÑ, а меÑоди генеÑаÑоÑа â Ñе Ñаме Ñе, Ñо оÑÑкÑÑ for..of:
- вÑн Ð¼Ð°Ñ Ð¼ÐµÑод
.next() - повеÑÑÐ°Ñ Ð·Ð½Ð°ÑÐµÐ½Ð½Ñ Ñ Ð²Ð¸Ð³Ð»ÑдÑ
{value: ..., done: true/false}
Це, звиÑайно, не випадковÑÑÑÑ. ÐенеÑаÑоÑи бÑли Ð´Ð¾Ð´Ð°Ð½Ñ Ð´Ð¾ мови JavaScript з ÑÑÐ°Ñ ÑваннÑм обâÑкÑÑв, Ñо пеÑебиÑаÑÑÑÑÑ, Ñоб ÑÑ Ð±Ñло легÑе ÑеалÑзÑваÑи.
ÐаÑÑÐ°Ð½Ñ Ð· генеÑаÑоÑом набагаÑо лаконÑÑнÑÑий, нÑж оÑигÑналÑний код range, Ñо пеÑебиÑаÑÑÑÑÑ, Ñ Ð·Ð±ÐµÑÑÐ³Ð°Ñ ÑÑ ÑÐ°Ð¼Ñ ÑÑнкÑÑоналÑнÑÑÑÑ.
У виÑÐµÐ½Ð°Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¿ÑÐ¸ÐºÐ»Ð°Ð´Ð°Ñ Ð¼Ð¸ ÑÑвоÑили кÑнÑÐµÐ²Ñ Ð¿Ð¾ÑлÑдовноÑÑÑ, але ми Ñакож можемо ÑÑвоÑиÑи генеÑаÑоÑ, Ñкий Ð²Ð¸Ð´Ð°Ñ Ð·Ð½Ð°ÑÐµÐ½Ð½Ñ Ð½ÐµÑкÑнÑенно. ÐапÑиклад, неÑкÑнÑенна поÑлÑдовнÑÑÑÑ Ð¿ÑÐµÐ²Ð´Ð¾Ð²Ð¸Ð¿Ð°Ð´ÐºÐ¾Ð²Ð¸Ñ ÑиÑел.
ÐезÑÑмнÑвно, Ð´Ð»Ñ ÑÑого бÑде поÑÑÑбно break (або return) Ñ ÑÐ¸ÐºÐ»Ñ for..of в ÑÐ°ÐºÐ¾Ð¼Ñ Ð³ÐµÐ½ÐµÑаÑоÑÑ. ÐнакÑе Ñикл повÑоÑÑваÑимеÑÑÑÑ Ð½ÐµÑкÑнÑенно Ñа завиÑне.
ÐомпозиÑÑÑ Ð³ÐµÐ½ÐµÑаÑоÑÑв
ÐомпозиÑÑÑ Ð³ÐµÐ½ÐµÑаÑоÑÑв â Ñе оÑобливÑÑÑÑ Ð³ÐµÐ½ÐµÑаÑоÑÑв, Ñо дозволÑÑ Ð¿ÑозоÑо âвбÑдовÑваÑиâ генеÑаÑоÑи один в одного.
ÐапÑиклад, Ñ Ð½Ð°Ñ Ñ ÑÑнкÑÑÑ, Ñка генеÑÑÑ Ð¿Ð¾ÑлÑдовнÑÑÑÑ ÑиÑел:
function* generateSequence(start, end) {
for (let i = start; i <= end; i++) yield i;
}
Ð¢ÐµÐ¿ÐµÑ Ð¼Ð¸ Ñ Ð¾ÑÑли б повÑоÑно викоÑиÑÑаÑи його Ð´Ð»Ñ ÑÑвоÑÐµÐ½Ð½Ñ ÑкладнÑÑÐ¾Ñ Ð¿Ð¾ÑлÑдовноÑÑÑ:
- ÑпоÑаÑÐºÑ ÑиÑÑи
0..9(з кодами ÑимволÑв 48â¦57), - за Ñкими йдÑÑÑ Ð²ÐµÐ»Ð¸ÐºÑ Ð»ÑÑеÑи алÑавÑÑÑ
A..Z(коди ÑимволÑв 65â¦90) - за Ñкими йдÑÑÑ Ð¼Ð°Ð»Ñ Ð»ÑÑеÑи алÑавÑÑÑ
a..z(коди ÑимволÑв 97â¦122)
Ðи можемо викоÑиÑÑовÑваÑи ÑÑ Ð¿Ð¾ÑлÑдовнÑÑÑÑ, напÑиклад ÑÑвоÑÑваÑи паÑолÑ, вибиÑаÑÑи з Ð½ÐµÑ Ñимволи (можна Ñакож додаÑи Ñимволи пÑнкÑÑаÑÑÑ), але давайÑе ÑпоÑаÑÐºÑ Ð·Ð³ÐµÐ½ÐµÑÑÑмо ÑÑ.
У звиÑайнÑй ÑÑнкÑÑÑ, Ñоб обâÑднаÑи ÑезÑлÑÑаÑи кÑлÑÐºÐ¾Ñ ÑнÑÐ¸Ñ ÑÑнкÑÑй, ми викликаÑмо ÑÑ , збеÑÑгаÑмо ÑезÑлÑÑаÑи, а поÑÑм обâÑднÑÑмо в кÑнÑÑ.
ÐÐ»Ñ Ð³ÐµÐ½ÐµÑаÑоÑÑв ÑÑнÑÑ ÑпеÑÑалÑний ÑинÑакÑÐ¸Ñ yield* Ð´Ð»Ñ âвбÑдовÑваннÑâ (компонÑваннÑ) одного генеÑаÑоÑа в ÑнÑий.
ÐÑÑ ÐºÐ¾Ð¼Ð¿Ð¾Ð·Ð¸ÑÑÑ Ð³ÐµÐ½ÐµÑаÑоÑÑв:
function* generateSequence(start, end) {
for (let i = start; i <= end; i++) yield i;
}
function* generatePasswordCodes() {
// 0..9
yield* generateSequence(48, 57);
// A..Z
yield* generateSequence(65, 90);
// a..z
yield* generateSequence(97, 122);
}
let str = '';
for(let code of generatePasswordCodes()) {
str += String.fromCharCode(code);
}
alert(str); // 0..9A..Za..z
ÐиÑекÑива yield* делегÑÑ Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ ÑнÑÐ¾Ð¼Ñ Ð³ÐµÐ½ÐµÑаÑоÑÑ. Цей ÑеÑмÑн ознаÑаÑ, Ñо yield* gen виконÑÑ ÑÑеÑаÑÑÑ Ð½Ð°Ð´ генеÑаÑоÑом gen Ñ Ð¿ÑозоÑо пеÑÐµÐ´Ð°Ñ Ð¹Ð¾Ð³Ð¾ виÑ
Ñд назовнÑ. ÐÑби знаÑÐµÐ½Ð½Ñ Ð±Ñли оÑÑÐ¸Ð¼Ð°Ð½Ñ Ð·Ð¾Ð²Ð½ÑÑнÑм генеÑаÑоÑом.
РезÑлÑÑÐ°Ñ Ñакий Ñамий, Ñк Ñкби ми вÑÑавили код Ñз Ð²ÐºÐ»Ð°Ð´ÐµÐ½Ð¸Ñ Ð³ÐµÐ½ÐµÑаÑоÑÑв:
function* generateSequence(start, end) {
for (let i = start; i <= end; i++) yield i;
}
function* generateAlphaNum() {
// yield* generateSequence(48, 57);
for (let i = 48; i <= 57; i++) yield i;
// yield* generateSequence(65, 90);
for (let i = 65; i <= 90; i++) yield i;
// yield* generateSequence(97, 122);
for (let i = 97; i <= 122; i++) yield i;
}
let str = '';
for(let code of generateAlphaNum()) {
str += String.fromCharCode(code);
}
alert(str); // 0..9A..Za..z
ÐомпозиÑÑÑ Ð³ÐµÐ½ÐµÑаÑоÑÑв â Ñе пÑиÑодний ÑпоÑÑб вÑÑавиÑи поÑÑк одного генеÑаÑоÑа в ÑнÑий. Ðона не викоÑиÑÑовÑÑ Ð´Ð¾Ð´Ð°ÑÐºÐ¾Ð²Ñ Ð¿Ð°Ð¼âÑÑÑ Ð´Ð»Ñ Ð·Ð±ÐµÑÑÐ³Ð°Ð½Ð½Ñ Ð¿ÑомÑÐ¶Ð½Ð¸Ñ ÑезÑлÑÑаÑÑв.
âyieldâ â доÑога з двоÑÑоÑоннÑм ÑÑÑ Ð¾Ð¼
Ðо ÑÑого моменÑÑ Ð³ÐµÐ½ÐµÑаÑоÑи бÑли ÑÑ Ð¾Ð¶Ñ Ð½Ð° обâÑкÑи, Ñо пеÑебиÑаÑÑÑÑÑ, Ð·Ñ ÑпеÑÑалÑним ÑинÑакÑиÑом Ð´Ð»Ñ Ð³ÐµÐ½ÐµÑÑÐ²Ð°Ð½Ð½Ñ Ð·Ð½Ð°ÑенÑ. Ðле наÑпÑÐ°Ð²Ð´Ñ Ð²Ð¾Ð½Ð¸ набагаÑо поÑÑжнÑÑÑ Ð¹ гнÑÑкÑÑÑ.
Це ÑомÑ, Ñо yield Ñ Ð´Ð¾ÑÐ¾Ð³Ð¾Ñ Ð· двоÑÑоÑоннÑм ÑÑÑ
ом: вÑн не лиÑе повеÑÑÐ°Ñ ÑезÑлÑÑÐ°Ñ Ð½Ð°Ð·Ð¾Ð²Ð½Ñ, але Ñакож може пеÑедаÑи знаÑÐµÐ½Ð½Ñ Ð²ÑеÑÐµÐ´Ð¸Ð½Ñ Ð³ÐµÐ½ÐµÑаÑоÑа.
ÐÐ»Ñ ÑÑого ми Ð¿Ð¾Ð²Ð¸Ð½Ð½Ñ Ð²Ð¸ÐºÐ»Ð¸ÐºÐ°Ñи generator.next(arg) з аÑгÑменÑом. Цей аÑгÑÐ¼ÐµÐ½Ñ ÑÑÐ°Ñ ÑезÑлÑÑаÑом yield.
ÐодивÑмоÑÑ Ð½Ð° пÑикладÑ:
function* gen() {
// ÐеÑедаÑмо запиÑÐ°Ð½Ð½Ñ Ð·Ð¾Ð²Ð½ÑÑнÑÐ¾Ð¼Ñ ÐºÐ¾Ð´Ñ Ñа ÑекаÑмо вÑдповÑдÑ
let result = yield "2 + 2 = ?"; // (*)
alert(result);
}
let generator = gen();
let question = generator.next().value; // <-- yield повеÑÑÐ°Ñ Ð·Ð½Ð°ÑеннÑ
generator.next(4); // --> пеÑÐµÐ´Ð°Ñ ÑезÑлÑÑÐ°Ñ Ð² генеÑаÑоÑ
- ÐеÑÑий виклик
generator.next()завжди Ð¼Ð°Ñ Ð·Ð´ÑйÑнÑваÑиÑÑ Ð±ÐµÐ· аÑгÑменÑÑ (аÑгÑÐ¼ÐµÐ½Ñ ÑгноÑÑÑÑÑÑÑ, ÑкÑо вÑн пеÑеданий). ÐÑн ÑозпоÑÐ¸Ð½Ð°Ñ Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ Ñа повеÑÑÐ°Ñ ÑезÑлÑÑÐ°Ñ Ð¿ÐµÑÑогоyield "2+2=?". У Ñей Ð¼Ð¾Ð¼ÐµÐ½Ñ Ð³ÐµÐ½ÐµÑаÑÐ¾Ñ Ð·ÑпинÑÑ Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ, залиÑаÑÑиÑÑ Ð½Ð° ÑÑдкÑ(*). - ÐоÑÑм, Ñк показано на зобÑÐ°Ð¶ÐµÐ½Ð½Ñ Ð²Ð¸Ñе, ÑезÑлÑÑаÑ
yieldпоÑÑаплÑÑ Ð´Ð¾ змÑнноÑquestionÑ ÐºÐ¾Ð´Ñ, Ñо викликаÑ. - Ðа
generator.next(4)генеÑаÑÐ¾Ñ Ð²ÑдновлÑÑÑÑÑÑ, Ñ4поÑÑаплÑÑ Ñк ÑезÑлÑÑаÑ:let result = 4.
ÐаÑважÑе, Ñо зовнÑÑнÑй код не повинен негайно викликаÑи next(4). Це може зайнÑÑи ÑаÑ. Це не пÑоблема: генеÑаÑÐ¾Ñ Ð·Ð°ÑекаÑ.
ÐапÑиклад:
// вÑдновиÑи ÑобоÑÑ Ð³ÐµÐ½ÐµÑаÑоÑа ÑеÑез деÑкий ÑаÑ
setTimeout(() => generator.next(4), 1000);
Як баÑимо, на вÑдмÑÐ½Ñ Ð²Ñд звиÑайниÑ
ÑÑнкÑÑй, генеÑаÑÐ¾Ñ Ñ ÐºÐ¾Ð´, Ñо його викликаÑ, можÑÑÑ Ð¾Ð±Ð¼ÑнÑваÑиÑÑ ÑезÑлÑÑаÑами, пеÑедаÑÑи знаÑÐµÐ½Ð½Ñ Ð² next/yield.
Щоб зÑобиÑи ÑеÑÑ Ð±ÑлÑÑ Ð¾Ñевидними, оÑÑ ÑнÑий пÑиклад Ñз бÑлÑÑÐ¾Ñ ÐºÑлÑкÑÑÑÑ Ð²Ð¸ÐºÐ»Ð¸ÐºÑв:
function* gen() {
let ask1 = yield "2 + 2 = ?";
alert(ask1); // 4
let ask2 = yield "3 * 3 = ?"
alert(ask2); // 9
}
let generator = gen();
alert( generator.next().value ); // "2 + 2 = ?"
alert( generator.next(4).value ); // "3 * 3 = ?"
alert( generator.next(9).done ); // true
ÐобÑÐ°Ð¶ÐµÐ½Ð½Ñ Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ:
- ÐеÑÑий
.next()поÑÐ¸Ð½Ð°Ñ Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ⦠ÐÑн доÑÑÐ³Ð°Ñ Ð¿ÐµÑÑогоyield. - РезÑлÑÑÐ°Ñ Ð¿Ð¾Ð²ÐµÑÑаÑÑÑÑÑ Ð´Ð¾ зовнÑÑнÑого кодÑ.
- ÐÑÑгий
.next(4)пеÑедаÑ4назад Ñ Ð³ÐµÐ½ÐµÑаÑÐ¾Ñ Ñк ÑезÑлÑÑÐ°Ñ Ð¿ÐµÑÑогоyieldÑ Ð²ÑдновлÑÑ Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ. - â¦Ðоно доÑÑÐ³Ð°Ñ Ð´ÑÑгого
yield, Ñкий ÑÑÐ°Ñ ÑезÑлÑÑаÑом Ð²Ð¸ÐºÐ»Ð¸ÐºÑ Ð³ÐµÐ½ÐµÑаÑоÑа. - ТÑеÑÑй
next(9)пеÑедаÑ9Ñ Ð³ÐµÐ½ÐµÑаÑÐ¾Ñ Ñк ÑезÑлÑÑÐ°Ñ Ð´ÑÑгогоyieldÑ Ð²ÑдновлÑÑ Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ, Ñке доÑÑÐ³Ð°Ñ ÐºÑнÑÑ ÑÑнкÑÑÑ, ÑомÑdone: true.
Це Ñк гÑа в âпÑнг-понгâ. Ðожне next(value) (за винÑÑком пеÑÑого) пеÑÐµÐ´Ð°Ñ Ð·Ð½Ð°ÑÐµÐ½Ð½Ñ Ð² генеÑаÑоÑ, Ñке ÑÑÐ°Ñ ÑезÑлÑÑаÑом поÑоÑного yield, а поÑÑм повеÑÑÐ°Ñ ÑезÑлÑÑÐ°Ñ Ð½Ð°ÑÑÑпного yield.
generator.throw
Як ми помÑÑили Ñ Ð¿ÑикладаÑ
виÑе, зовнÑÑнÑй код може пеÑедаÑи знаÑÐµÐ½Ð½Ñ Ð² генеÑаÑоÑ, Ñк ÑезÑлÑÑÐ°Ñ yield.
â¦Ðле вÑн Ñакож може ÑнÑÑÑÑваÑи (викинÑÑи) Ñам помилкÑ. Це пÑиÑодно, оÑкÑлÑки помилка â Ñе Ñвого ÑÐ¾Ð´Ñ ÑезÑлÑÑаÑ.
Щоб пеÑедаÑи Ð¿Ð¾Ð¼Ð¸Ð»ÐºÑ Ð² yield, ми Ð¿Ð¾Ð²Ð¸Ð½Ð½Ñ Ð²Ð¸ÐºÐ»Ð¸ÐºÐ°Ñи generator.throw(err). У ÑÑÐ¾Ð¼Ñ Ð²Ð¸Ð¿Ð°Ð´ÐºÑ err викидаÑÑÑÑÑ Ð² ÑÑдок Ñз Ñим yield.
ÐапÑиклад, ÑÑÑ "2 + 2 = ?" пÑизводиÑÑ Ð´Ð¾ помилки:
function* gen() {
try {
let result = yield "2 + 2 = ?"; // (1)
alert("ÐÐ¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ Ð½Ðµ доÑ
одиÑÑ ÑÑди, ÑÐ¾Ð¼Ñ Ñо виÑе викинÑÑо винÑÑок");
} catch(e) {
alert(e); // покаже помилкÑ
}
}
let generator = gen();
let question = generator.next().value;
generator.throw(new Error("ÐÑдповÑÐ´Ñ Ð½Ðµ знайдено в моÑй Ð±Ð°Ð·Ñ Ð´Ð°Ð½Ð¸Ñ
")); // (2)
Ðомилка, Ñка пÑокидаÑÑÑÑÑ Ð² генеÑаÑÐ¾Ñ Ð½Ð° ÑÑÐ´ÐºÑ (2), пÑизводиÑÑ Ð´Ð¾ винÑÑÐºÑ Ð½Ð° ÑÑÐ´ÐºÑ (1) з yield. У виÑÐµÐ½Ð°Ð²ÐµÐ´ÐµÐ½Ð¾Ð¼Ñ Ð¿ÑÐ¸ÐºÐ»Ð°Ð´Ñ try..catch ловиÑÑ Ñа показÑÑ Ð¹Ð¾Ð³Ð¾.
ЯкÑо ми його не зловимо, Ñо, Ñк Ñ Ð±ÑдÑ-Ñкий винÑÑок, вÑн âвипадаÑâ з генеÑаÑоÑа Ñ ÐºÐ¾Ð´, Ñо його викликав.
ÐоÑоÑний ÑÑдок кодÑ, Ñо Ð²Ð¸ÐºÐ»Ð¸ÐºÐ°Ñ â Ñе ÑÑдок Ñз generator.throw, познаÑений Ñк (2). Тож ми можемо зловиÑи ÑÑ ÑÑÑ, напÑиклад:
function* generate() {
let result = yield "2 + 2 = ?"; // Ðомилка в ÑÑÐ¾Ð¼Ñ ÑÑдкÑ
}
let generator = generate();
let question = generator.next().value;
try {
generator.throw(new Error("ÐÑдповÑÐ´Ñ Ð½Ðµ знайдено в моÑй Ð±Ð°Ð·Ñ Ð´Ð°Ð½Ð¸Ñ
"));
} catch(e) {
alert(e); // покаже помилкÑ
}
ЯкÑо ми не пеÑÐµÑ Ð¾Ð¿Ð¸Ð¼Ð¾ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÑ Ñам, Ñо далÑ, Ñк зазвиÑай, вона поÑÑаплÑÑ Ð´Ð¾ зовнÑÑнÑого ÐºÐ¾Ð´Ñ (ÑкÑо Ñ) Ñ, ÑкÑо не пеÑÐµÑ Ð¾Ð¿Ð»ÐµÐ½Ð°, Ð²Ð±Ð¸Ð²Ð°Ñ ÑкÑипÑ.
generator.return
generator.return(value) завеÑÑÑÑ Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ Ð³ÐµÐ½ÐµÑаÑоÑа Ñа повеÑÑÐ°Ñ Ð·Ð°Ð´Ð°Ð½Ðµ value.
function* gen() {
yield 1;
yield 2;
yield 3;
}
const g = gen();
g.next(); // { value: 1, done: false }
g.return('foo'); // { value: "foo", done: true }
g.next(); // { value: undefined, done: true }
ЯкÑо ми Ð·Ð½Ð¾Ð²Ñ Ð²Ð¸ÐºÐ¾ÑиÑÑаÑмо generator.return() Ñ Ð·Ð°Ð²ÐµÑÑÐµÐ½Ð¾Ð¼Ñ Ð³ÐµÐ½ÐµÑаÑоÑÑ, вÑн Ð·Ð½Ð¾Ð²Ñ Ð¿Ð¾Ð²ÐµÑне Ñе знаÑÐµÐ½Ð½Ñ (MDN).
ЧаÑÑо ми не викоÑиÑÑовÑÑмо його, оÑкÑлÑки в бÑлÑÑоÑÑÑ Ð²Ð¸Ð¿Ð°Ð´ÐºÑв Ñ Ð¾Ñемо оÑÑимаÑи вÑÑ Ð·Ð½Ð°ÑеннÑ, Ñо повеÑÑаÑÑÑÑÑ, але Ñе може бÑÑи коÑиÑно, коли ми Ñ Ð¾Ñемо зÑпиниÑи генеÑаÑÐ¾Ñ Ñ Ð¿ÐµÐ²Ð½Ð¾Ð¼Ñ ÑÑанÑ.
ÐÑдÑÑмки
- ÐенеÑаÑоÑи ÑÑвоÑÑÑÑÑÑÑ ÑÑнкÑÑÑми-генеÑаÑоÑами
function* f(â¦) {â¦}. - УÑеÑÐµÐ´Ð¸Ð½Ñ Ð³ÐµÐ½ÐµÑаÑоÑÑв (лиÑе в ниÑ
) ÑÑнÑÑ Ð¾Ð¿ÐµÑаÑоÑ
yield. - ÐовнÑÑнÑй код Ñ Ð³ÐµÐ½ÐµÑаÑÐ¾Ñ Ð¼Ð¾Ð¶ÑÑÑ Ð¾Ð±Ð¼ÑнÑваÑиÑÑ ÑезÑлÑÑаÑами за Ð´Ð¾Ð¿Ð¾Ð¼Ð¾Ð³Ð¾Ñ Ð²Ð¸ÐºÐ»Ð¸ÐºÑв
next/yield.
У ÑÑÑаÑÐ½Ð¾Ð¼Ñ JavaScript генеÑаÑоÑи викоÑиÑÑовÑÑÑÑÑÑ ÑÑдко. Ðле ÑÐ½Ð¾Ð´Ñ Ð²Ð¾Ð½Ð¸ ÑÑаÑÑÑ Ñ Ð¿ÑигодÑ, оÑкÑлÑки здаÑнÑÑÑÑ ÑÑнкÑÑÑ Ð¾Ð±Ð¼ÑнÑваÑиÑÑ Ð´Ð°Ð½Ð¸Ð¼Ð¸ з кодом, Ñо ÑÑ Ð²Ð¸ÐºÐ»Ð¸ÐºÐ°Ñ, пÑд ÑÐ°Ñ Ñамого Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ Ñ Ð´Ð¾ÑиÑÑ ÑнÑкалÑноÑ. Ð, безÑÑмнÑвно, вони ÑÑдово пÑÐ´Ñ Ð¾Ð´ÑÑÑ Ð´Ð»Ñ ÑÑвоÑÐµÐ½Ð½Ñ Ð¾Ð±âÑкÑÑв, Ñо пеÑебиÑаÑÑÑÑÑ.
ÐÑÑм Ñого, Ñ Ð½Ð°ÑÑÑÐ¿Ð½Ð¾Ð¼Ñ ÑоздÑÐ»Ñ Ð¼Ð¸ ознайомимоÑÑ Ð· аÑинÑ
Ñонними генеÑаÑоÑами, ÑÐºÑ Ð²Ð¸ÐºÐ¾ÑиÑÑовÑÑÑÑÑÑ Ð´Ð»Ñ Ð·ÑиÑÑÐ²Ð°Ð½Ð½Ñ Ð¿Ð¾ÑокÑв аÑинÑ
Ñонно згенеÑованиÑ
даниÑ
(напÑиклад, ÑÐºÑ Ð¿Ð¾ÑÑоÑÑнково заванÑажÑÑÑÑÑÑ Ð· меÑежÑ) Ñ ÑиклаÑ
for await ... of.
У вебпÑогÑамÑÐ²Ð°Ð½Ð½Ñ Ð¼Ð¸ ÑаÑÑо пÑаÑÑÑмо з поÑоковими даними, ÑÐ¾Ð¼Ñ Ñе Ñе один дÑже важливий ваÑÑÐ°Ð½Ñ Ð²Ð¸ÐºÐ¾ÑиÑÑаннÑ.
ÐоменÑаÑÑ
<code>, Ð´Ð»Ñ ÐºÑлÑÐºÐ¾Ñ ÑÑдкÑв â обгоÑнÑÑÑ ÑÑ Ñегом<pre>, Ð´Ð»Ñ Ð¿Ð¾Ð½Ð°Ð´ 10 ÑÑдкÑв â викоÑиÑÑовÑйÑе пÑÑоÑниÑÑ (plnkr, jsbin, codepenâ¦)