javascript
一个很简短的 JS 生成器入门和用法参考
生成器函數(shù)
在寫其他 js 代碼時會經(jīng)常用到 debugger 的東西,能夠讓當前運行的函數(shù)暫停住。生成器函數(shù)里的 yield 關(guān)鍵詞也能使得函數(shù)暫停運行,同時還能用來做數(shù)據(jù)的輸入輸出(如果是 debugger,只能手動去逐個 inspect 變量)。
yield 可以當作“斷點”。yield value 除了能當作斷點,還可以向外部輸出 value。
此外,yield 表達式本身也是可以有值的,也就是說還可以表示外部傳入的數(shù)據(jù)。只要外部在調(diào)用 next(inputValue) 時輸入一個值。 這就是為什么在賦值語句里,可以用 yield 作為右值(例如,在使用了 react-saga 的項目里到處都是這種玩意兒)。
function* fn1(){var data = yield "字符串反轉(zhuǎn)器已啟動"yield data.split("").reverse().join("") }// 創(chuàng)建 Generator 對象 var g = fn1()// 運行函數(shù),直到遇到第一個“斷點”(yield 處) console.log(g.next())// 上次停頓的位置是 var data = yield "字符串反轉(zhuǎn)器已啟動" // 因此可以在繼續(xù)運行前,使得 (yield "字符串反轉(zhuǎn)器已啟動") 的值為 "Hello" console.log(g.next("Hello")) // 輸出: // { value: '字符串反轉(zhuǎn)器已啟動', done: false } // { value: 'olleH', done: false } 復(fù)制代碼Generator
正如前面的示例,調(diào)用一個 function* 生成器函數(shù),會返回一個 Generator 對象(上文的 g)。這個對象是可迭代對象(最常見的用法,即用于 for of 循環(huán)中)。
此外,可以把它當作一個控制器,控制著一個被 yield 打了斷點(而且還沒開始運行)的函數(shù)。
Generator 其具備下列方法:
- (從頭,或者從上次停止的位置)開始運行生成器函數(shù)體,直到遇到 yield 或者 return
- 注意:此函數(shù)可以有一個可選的參數(shù) inputValue 。可以在繼續(xù)運行生成器函數(shù)前,為上次停頓所在的 yield 表達式設(shè)置一個值。
- 如果生成器函數(shù)沒開始運行,則等同于原地 throw
- 否則,在生成器函數(shù)體當前 yield 停頓的位置 throw 一個異常,然后繼續(xù)運行,直到遇到 yield 、 return 或者未被捕獲的異常(見下文)
- 強行終止(即使生成器函數(shù)還沒運行完畢),并指定一個 value 作為返回值
- 用于迭代協(xié)議的。效果同直接調(diào)用 next()
yield*
和 yield 關(guān)鍵詞相比,多了一個星號。可以把 yield* another_iterable 當作以下代碼語法糖:
for (let item of another_iterable) {yield item; } 復(fù)制代碼也就是說,在生成器函數(shù)里, yield* 就是針對一個可迭代對象,把它的每一項逐個地 yield 出來。
有趣的例子:
- yield* [1,2,3] 會把3個數(shù)字逐個 yield 出來。數(shù)組是可迭代的。
- yield* "abcdefg" 會把這7個字母逐個 yield 出來。字符串也是可迭代對象。
- yield* another_generator 相當于把另一個 Generator 的輸出,當作自己的輸出給一個個 yield 出去了。
- 這個有趣的特性可以用來做攔截器之類的應(yīng)用。
- 說到了串聯(lián),如果是當前生成器函數(shù)想要利用另外一個生成器的返回值,直接調(diào)用 another_generator.next().value 就行了
生成器函數(shù)內(nèi)的異常
由 next() 或者 throw(e) 可以讓生成器函數(shù)開始運行。在運行過程中,如果生成器函數(shù)里遇到了未被捕獲的異常(可以是生成器內(nèi)部自己產(chǎn)生的,或者由外部調(diào)用 throw(e) 塞進去的),那么會在外部由 next() 或者 throw(e) 給 throw 出來
function* test(){try {console.log("inner: Hello")console.log("inner: GET" + (yield "output1"))} catch (err) {console.log("inner: Caught", err)}console.log("inner: Done")return "output 2" }var g = test() console.log("outer: next: ", g.next("input 1")) console.log("outer: throw: ", g.throw("err")) console.log("outer: next: ", g.next("input 2")) 復(fù)制代碼上面的例子輸出如下。注意到由外部提供的 input1 不會被輸出,因為那是生成器函數(shù)還沒開始運行的時候傳進去的,能傳到哪里?沒有任何的意義。
inner: Hello outer: next: { value: 'output1', done: false } inner: Caught err inner: Done outer: throw: { value: 'output 2', done: true } outer: next: { value: undefined, done: true } 復(fù)制代碼安利
寫了一個 Markdown 編輯器組件,只要一個框,所見即所得,而且還全面兼容 CodeMirror(一個很強大的代碼編輯組件)
悄悄安利一下: laobubu.net/HyperMD/
(歡迎來 GitHub 點贊 或者幫我買杯咖啡)
總結(jié)
以上是生活随笔為你收集整理的一个很简短的 JS 生成器入门和用法参考的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HashMap的容量(桶的数量)为什么要
- 下一篇: 网络安全-XSS笔记