js--生成器總結
前言
生成器gengrator是es6 新增的函式功能,它允許你定義一個包含自有迭代演算法的函式, 同時它可以自動維護自己的狀態。 本文來總結一下JavaScript 中生成器的相關知識點。
正文
1、 生成器是什麼
生成器函式提供了一個強大的選擇:它允許你定義一個包含自有迭代演算法的函式, 同時它可以自動維護自己的狀態。 生成器函式使用function*
語法編寫。 最初呼叫時,生成器函式不執行任何程式碼,而是返回一種稱為Generator的迭代器。 通過呼叫生成器的下一個方法消耗值時,Generator函式將執行,直到遇到yield關鍵字。
2、 生成器例項( 通過yield 中斷執行)
(1)普通生成器函式
呼叫生成器函式會產生一個類似於迭代器的生成器物件,。生成器物件一開始處於暫停執行(suspended)的狀態。與迭代器相似,生成器物件也實現了 Iterator 介面,它們預設的迭代器是自引用的,因此具有 next() 方法。呼叫這個方法會讓生成器開始執行,遇到yield關鍵字函式暫停,再次呼叫next()繼續執行函式,yield並不回像return 一樣立即結束函式,只是暫停這個生成器函式。
注意:箭頭函式不能用來定義生成器函式
function* createIterator() { yield 1; yield2; yield 3; } console.log(createIterator());// createIterator {<suspended>} console.log(createIterator()[Symbol.iterator]());// createIterator {<suspended>},因此可以通過生成器建立迭代器函式 let iterator = createIterator() console.log(iterator.next().value);//1 console.log(iterator.next().value);//2 console.log(iterator.next().value);//3
(2)函式表示式的生成器函式,使用函式表示式來建立一個生成器
let myIterator = function* (items) { for (let i = 0; i < items.length; i++) { yield items[i] } } let myIterator1 = myIterator([1, 2, 3]) console.log(myIterator1.next().value);//1 console.log(myIterator1.next().value);//2 console.log(myIterator1.next().value);//3
(3)物件型別的生成器函式
var obj = { createIterator: function* (item) { for (let i = 0; i < items.length; i++) { yield items[i] } } } // 也可以 var obj = { *createIterator(items) { for (let i = 0; i < items.length; i++) { yield items[i] } } }
生成器會在每個yield 語句後停止執行,在函式中停止執行的能力是極其強大的,yield 關鍵字指定了迭代器在被呼叫next的方法是應當按順序返回的值,在沒有呼叫next() 方法的時候,生成器函式裡的的程式碼並不會執行,同時也可用通過return 返回生成器函式的返回值,如下:
function* generatorFn() { console.log("start") yield 'foo'; yield; yield 'bar'; return 'baz'; } let generatorObject = generatorFn(); console.log(generatorObject.next()); //start { done: false, value: 'foo' } console.log(generatorObject.next()); // { done: false, value: undefined } console.log(generatorObject.next()); // { done: false, value: 'bar' } console.log(generatorObject.next()); // { done: true, value: 'baz' }
3、 yield關鍵字詳解
(1) yield 關鍵字可以和值或者是表示式在一起使用,因此可以通過生成器給迭代器新增專案,而不是機械化地將專案一個個列出。
// for迴圈內部使用yield關鍵字 function* createIterator2(items) { //let 塊級作用域 for (let i = 0; i < items.length; i++) { yield items[i] } } let iterator2 = createIterator2([1, 2, 3]) console.log(iterator2.next());//{value:1,done:false} console.log(iterator2.next());//{value:2,done:false} console.log(iterator2.next());//{value:3,done:false} console.log(iterator2.next());//{value:undefined,done:true}
注意 :yield 關鍵字只能用於生成器內部,用於其他位置會出現語法錯誤,即使在生成器內部的函式中也不行,下面的程式碼報錯。
// yield無法穿越函式邊界,在一個巢狀函式中無法將值返回給包含它的函式 // function* createIterator2(items) { // items.forEach(item => { // yield item +1//語法錯誤 // }); // }
(2) yield 關鍵字還可以作為函式的中間引數使用
使用 yield 實現輸入和輸出, yield 關鍵字還可以作為函式的中間引數使用,上一次讓生成器函式暫停的 yield 關鍵字會接收到傳給 next() 方法的第一個值。第一次呼叫 next() 傳入的值不會被使用,因為這一次呼叫是為了開始執行生成器函式
function* generatorFn(initial) { console.log(initial); console.log(yield); console.log(yield); } let generatorObject = generatorFn('foo'); generatorObject.next('bar'); // foo generatorObject.next('baz'); // baz generatorObject.next('qux'); // qux // yield 關鍵字可以同時用於輸入和輸出,如下 function* generatorFn() { return yield 'foo'; } let generatorObject = generatorFn(); console.log(generatorObject.next()); // { done: false, value: 'foo' } console.log(generatorObject.next('bar')); // { done: true, value: 'bar' }
4、 yield* 委託給其他生成器或者可迭代物件
(1)yield* 委託給其他可迭代物件
可以使用星號增強 yield 的行為,讓它能夠迭代一個可迭代物件,從而一次產出一個值,因為 yield * 實際上只是將一個可迭代物件序列化為一連串可以單獨產出的值,所以這跟把 yield放到一個迴圈裡沒什麼不同。下面兩個生成器函式的行為是等價的:
function* generatorFnA() { for (const x of [1, 2, 3]) { yield x; } } console.log(generatorFnA()); for (const x of generatorFnA()) { console.log(x); } // 1 // 2 // 3 function* generatorFnB() { yield* [1, 2, 3]; } for (const x of generatorFnB()) { console.log(x); } // 1 // 2 // 3
(2)yield* 委託給其他生成器
function* createNumberIterator() { yield 1; yield 2; return 3; } function* createRepeatingIterator(count) { for (let i = 0; i < count; i++) { yield "repeat"; } } function* createCombinedIterator() { let result = yield* createNumberIterator(); yield result; yield* createRepeatingIterator(result); } var iterator = createCombinedIterator(); console.log(iterator.next()); // "{ value: 1, done: false }" console.log(iterator.next()); // "{ value: 2, done: false }" console.log(iterator.next()); // "{ value: 3, done: false }" console.log(iterator.next()); // "{ value: "repeat", done: false }" console.log(iterator.next()); // "{ value: "repeat", done: false }" console.log(iterator.next()); // "{ value: "repeat", done: false }" console.log(iterator.next()); // "{ value: undefined, done: true }"
上面的程式碼中createCombinedIterator()生成器委託了 createNumberIterator 生成器,並將它的返回值賦值給了result變數,yeild result 輸入該變數值3,result變數接下來作為引數傳遞 createRepeatingIterator()生成器,提示同一字串需要呼叫3次。
寫在最後
以上就是本文的全部內容,希望給讀者帶來些許的幫助和進步,方便的話點個關注,小白的成長之路會持續更新一些工作中常見的問題和技術點。