「javascript高級プログラム設計」学習ノート𞓜7.3.ジェネレータ
60774 ワード
「先端の民謡」に注目し、より多くのオリジナル技術文章を読む.
生成器 ES 6に追加された構造は、1つの関数ブロック内でコードの実行を一時停止して復元することができ、カスタマイズしたディエテンダーと協働 を実現することができます.
関連コード→
ジェネレータベース生成器の形式は関数であり、関数名の前に星番号 を追加する.は、関数の場所を定義することができ、すべてジェネレータ(矢印関数を除く) を定義することができます.ジェネレータ関数を呼び出すとジェネレータオブジェクトが生成され、生成器オブジェクトはIteratorインターフェースを実現し、 を有する. と同様である.関数体が空のジェネレータから一度 になります.は、生成器関数の戻り値により を指定することができる.ジェネレータ関数は、 生成器オブジェクトは、自己参照 であるIterableインターフェースを実現する. 生成器が を実行する.は に保持される.実行を停止したジェネレータ関数は、ジェネレータオブジェクト呼び出し を再開する.
が にあります.が にあります.
同一のジェネレータ関数の異なるジェネレータオブジェクト間には連絡がなく、一つのジェネレータオブジェクト上で に影響を与えない. にエラーが発生します.は、生成対象を反復可能なオブジェクトとして扱う .生成器を用いて反復サイクルの回数を制御する は、関数としての中間戻り文に加えて、 前回、ジェネレータ関数を一時停止させた を受信する.最初の呼び出し の実行を開始するためだけに使用されない.
を停止します. に戻る.
を使用します.は、反復回数に応じて対応するインデックス を生成する.生成器を用いた実現範囲 生成器を用いた充填配列 ジェネレータを使用してフィボナッチの数列を実現する は、星番号 に順次並べ替える. は、一般的なローズマリーの場合、 である.は、ジェネレータ関数によって生成されたローズマリーに対して、 .は を生成することができる.生成器オブジェクトは、 を生成する.一つの がある. .は、 である. エラーが処理されていない場合、生成器は を閉じる.エラーが発生器関数内部で処理されれば、生成器は閉じられず、実行を再開することができる.エラー処理は対応する をスキップします.ジェネレータとは?どの関数がジェネレータを定義できますか? ジェネレータオブジェクトはどうやって取得しますか?ジェネレータnext()メソッドのvalue戻り値をどう指定しますか?ジェネレータ関数はいつから実行されますか? は、「生成器オブジェクトのデフォルトのディケンサは自己参照」をどう理解しますか? yieldキーワードのジェネレータにおける役割は何ですか?リセットキーとの戻り値は何が違いますか? 同じジェネレータ方法で生成された異なるジェネレータオブジェクト間に連絡がありますか? ジェネレータ関数とyieldキーワードを使って、それぞれコードで以下の機能を実現してください. は5回反復して、各反復値とインデックス を取得する.は、3より9未満の整数 を取得する.は、1から6の自己増加配列 を充填する.フィボナッチ数列第20項の数字の値を求めます.(0から計算します.) はどのようにして生成器をデフォルトのローズマリーとして使うのですか?return()とthrow()の方法で、ジェネレータを早期終了させる方法はそれぞれ何ですか?
生成器
関連コード→
ジェネレータベース
*
function* generatorFn() {
} //
let gfn = function* () {
} //
let foo = {
*generatorFn() {
}, //
}
class Foo {
*generatorFn() {
} //
}
class FooStatic {
static *generatorFn() {
} //
}
next()
方法const g = generatorFn() // ,
console.log(g) // generatorFn {},
console.log(g.next) // next()
next()
方法の戻り値は、ドーン属性とvalue属性next()
を呼び出すとdone:true
状態console.log(g.next()) // { value: undefined, done: true },
value
の戻り値(デフォルトはundefined)function* generatorFn2() {
return 'foo'
}
const g2 = generatorFn2()
console.log(g2.next()) // { value: 'foo', done: true }
console.log(g2.next()) // { value: undefined, done: true },
next()
メソッドを初回起動した後だけ実行を開始します.function* generatorFn3() {
console.log(' ')
}
const g3 = generatorFn3() // , ( , )
g3.next() // ' ', next() , ,
function* generatorFn4() {
}
console.log(generatorFn4) // ƒ* generatorFn4() {},
const g4 = generatorFn4()
console.log(g4) // generatorFn4 {},
console.log(g4[Symbol.iterator]) // ƒ [Symbol.iterator]() { [native code] },
console.log(g4[Symbol.iterator]()) // generatorFn4 {},
console.log(g4 === g4[Symbol.iterator]()) // true,
yieldによる実行中断yield
キーワードは、生成器を停止させ、実行を開始させることができる.yield
キーワードに出会う前に正常にyield
キーワードに遭遇してから実行を停止し、関数領域の状態はnext()
方法によりfunction* generatorFn5() {
yield
}
let g5 = generatorFn5()
console.log(g5.next()) // { value: undefined, done: false },yield
console.log(g5.next()) // { value: undefined, done: true },
yield
キーワードは、関数のreturn
文と同様に機能し、その生成値はnext()
方法で返されたオブジェクトに現れるが、done
の状態は異なる.yield
キーワードで終了したジェネレータ関数はdone:false
状態return
キーワードで終了したジェネレータ関数はdone:true
状態function* generatorFn6() {
yield 'foo'
yield 'bar'
return 'baz'
}
let g6 = generatorFn6()
console.log(g6.next()) // { value: 'foo', done: false },yield
console.log(g6.next()) // { value: 'bar', done: false },yield
console.log(g6.next()) // { value: 'baz', done: true },return
next()
を呼び出す方法は他のジェネレータlet g7 = generatorFn6() // g7
let g8 = generatorFn6() // g8
console.log(g7.next()) // { value: 'foo', done: false }
console.log(g8.next()) // { value: 'foo', done: false }
console.log(g8.next()) // { value: 'bar', done: false }
console.log(g7.next()) // { value: 'bar', done: false }
yield
キーワードは、ジェネレータ関数の内部にある必要があります.直接にジェネレータ関数の定義に使用され、他の場所やネスト用の非ジェネレータ関数はfunction* validGeneratorFn() {
yield 'result'
}
function* invalidGeneratorFnA() {
function a() {
yield 'result' // SyntaxError: Unexpected string
}
}
function* invalidGeneratorFnB() {
const b = () => {
yield 'result' // SyntaxError: Unexpected string
}
}
function* invalidGeneratorFnC() {
;(() => {
yield 'result' // SyntaxError: Unexpected string
})()
}
ジェネレータオブジェクトをイテレーションオブジェクトとして使用します.function* generatorFn7() {
//
yield 1
yield 2
yield 3
}
for (const x of generatorFn7()) {
// generatorFn7,generatorFn7()
console.log(x)
/*
1
2
3
*/
}
function* nTimes(n) {
while (n--) {
console.log(n)
yield
}
}
for (let _ of nTimes(3)) {
console.log(_)
/*
2, 1 n
undefined, 1 yield
1, 2 n
undefined, 2 yield
0, 3 n
undefined, 3 yield
*/
}
yieldを使って入力と出力を実現します.yield
キーワードを関数の中間パラメータとして使用することもできる.yield
のキーワードは、next()
方法に伝達された最初の値next()
から入力された値は、ジェネレータ関数function* generatorFn8() {
console.log(yield)
console.log(yield)
console.log(yield)
}
let g9 = generatorFn8() // ,
g9.next('bar') // next() ,
g9.next('baz') // 'baz', next() baz, yield
g9.next('qux') // 'qux', next() qux, yield
yield
キーワードを入力と出力に同時に使用する(return
キーワードと同時に使用する)next()
方法にはパラメータがありません.yield
キーワードに遭遇したらnext()
方法にはパラメータがあり、同じyiieldに渡す値としてパラメータがあり、生成器関数実行return
は今回のエントリの値function* generatorFn9() {
return yield 'foo'
}
let g10 = generatorFn9()
console.log(g10.next()) // { value: 'foo', done: false },next() , yield ,
console.log(g10.next('bar')) // { value: 'bar', done: true },next() , yield , return 'bar'
yield
キーワードは何回もfunction* generatorFn10() {
for (let i = 0; ; i++) {
yield i
}
}
let g11 = generatorFn10()
console.log(g11.next()) // { value: 0, done: false }
console.log(g11.next()) // { value: 1, done: false }
console.log(g11.next()) // { value: 2, done: false }
console.log(g11.next()) // { value: 3, done: false }
function* nTimes(n) {
let i = 0
while (n--) {
yield i++
}
}
for (let x of nTimes(3)) {
console.log(x)
/*
0
1
2
*/
}
function* range(start, end) {
while (end > start) {
yield start++
}
}
for (const x of range(4, 7)) {
console.log(x)
/*
4
5
6
*/
}
function* zeros(n) {
while (n--) {
yield 0
}
}
console.log(zeros(8)) // zeros {},
console.log(Array.from(zeros(8))) // [0, 0, 0, 0, 0, 0, 0, 0],
function* fibonacci() {
let arr = [0, 1]
let [prev, curr] = arr
while (true) {
;[prev, curr] = [curr, prev + curr]
arr.push(curr)
yield arr
}
}
function Fibonacci(n) {
if (n === 1) {
// 1
return 0
} else if (n === 2 || n === 3) {
// 2、3
return 1
} else {
// 4
let num = 0
const fibo = fibonacci()
for (let i = 3; i <= n; i++) {
num = fibo.next().value
}
return num
}
}
console.log(Fibonacci(8).join()) // 0,1,1,2,3,5,8,13
反復可能なオブジェクトを生成*
でyield
を強化し、反復可能なオブジェクトを反復することができるようにし、yield*
は、反復可能なオブジェクトを一連の個別出力の値function* generatorFn11() {
yield* [1, 2, 3]
}
let g12 = generatorFn11()
for (const x of generatorFn11()) {
console.log(x)
/*
1
2
3
*/
}
//
function* generatorFn11() {
for (const x of [1, 2, 3]) {
yield x
}
}
yield*
の値は、*関連のディナリーがdone:true
**に戻るときのvalue
の属性である.done:true
は、ローズマリーの消耗を表し、この値はundefined
function* generatorFn12() {
console.log('iterValue', yield* [1, 2, 3])
}
for (const x of generatorFn12()) {
console.log('value', x)
/*
value 1
value 2
value 3
iterValue undefined
*/
}
done:true
の値は、リターンの値である(return値がないとundefinedに戻る)function* innerGeneratorFn() {
yield 'foo'
return 'bar'
}
function* outerGeneratorFn() {
console.log('iterValue', yield* innerGeneratorFn())
}
for (const x of outerGeneratorFn()) {
console.log('value', x)
/*
value foo
iterValue bar
*/
}
yield*
を使用して、再帰的アルゴリズムを実現する.yield*
で再帰を実現し、このとき、生成器は自身function* nTimes(n) {
if (n > 0) {
yield* nTimes(n - 1) //
yield n
}
}
for (const x of nTimes(3)) {
console.log(x)
/*
1
2
3
*/
}
生成器をデフォルトのディケンサとして使用します.Iterable
インターフェースを実現し、生成器関数とデフォルトのディケンサが起動された後、ディケンサclass Foo2 {
// Foo ,
constructor() {
this.values = [1, 2, 3]
}
*[Symbol.iterator]() {
yield* this.values
}
}
const f = new Foo2() //
for (const x of f) {
console.log(x)
/*
1
2
3
*/
}
事前終了ジェネレータIterator
インターフェースを実現するオブジェクトは、必ずnext()
方法があり、もう一つのオプションのreturn()
方法があり、生成器は第3の方法throw()
return()
およびthrow()
は、いずれも、強制生成器が閉状態に入るために使用されてもよいfunction* generatorFn13() {
}
let g13 = generatorFn13() //
console.log(g13.next) // ƒ next() { [native code] }
console.log(g13.return) // ƒ return() { [native code] }
console.log(g13.throw) // ƒ throw() { [native code] }
returnreturn()
方法は、様々なサブジェネレータオブジェクトの値(すなわち、return()方法のパラメータを返す.function* generatorFn14() {
yield* [1, 2, 3]
}
let g14 = generatorFn14()
console.log(g14) // generatorFn14 {}
console.log(g14.return(5)) // {value: 5, done: true}
console.log(g14) // generatorFn14 {}
return()
方式でクローズ状態のジェネレータオブジェクトに入り、後続の呼び出しnext()
は、done:true
状態を表示し、後続の提供された任意の戻り値は、もはや記憶されたり、伝播されたりしない.console.log(g14.next()) // { value: undefined, done: true }, return()
console.log(g14.next()) // { value: undefined, done: true }
console.log(g14.next()) // { value: undefined, done: true }
for-of
などの内蔵言語構造は、done:true
の重機オブジェクト内部の戻り値を無視する(undefinedを無視する)let g15 = generatorFn14()
for (const x of g15) {
x > 1 && g15.return() // x 1
console.log(x)
/*
1
2
done:true value(undefined)
*/
}
throwthrow()
方法は、一時停止時に、提供されたエラーをジェネレータオブジェクトに注入する.function* generatorFn15() {
yield* [1, 2, 3]
}
let g16 = generatorFn15()
console.log(g16) // generatorFn15 {}
try {
g16.throw('foo') //
} catch (err) {
console.log(err) // 'foo'
}
console.log(g16) // generatorFn15 {}, ,
yield
function* generatorFn16() {
for (const x of [1, 2, 3]) {
// try/catch -> ( )
// , throw()
try {
yield x // yield
} catch (err) {
console.log(err) // 'foo'
}
}
}
let g17 = generatorFn16()
console.log(g17.next()) // { value: 1, done: false }
g17.throw('foo') //
console.log(g17.next()) // { value: 3, done: false }, yield
まとめ&質問yield*
の役割は何ですか?普通のローズマリー、ジェネレータ関数によって生成されたローズマリーにおいて、yield*
の値はそれぞれ何ですか?