摘要:在生成器中使用語句生成器也是函數,所以它也可以使用語句。只是由于生成器本身的特性,其內部的的行為會和一般函數有些差別。
前面2篇系列文章講解了迭代器和生成器的最常用,最基礎的用法;這篇來討論迭代器和生成器的一些稍稍高級一點的用法:
1: 給迭代器的next()方法傳參 2: 從迭代器中拋出錯誤 3: 在生成器中使用return語句 4: 委托生成器(組合生成器或者生成器組合?)
1: 給迭代器的next()方法傳參
在前面2篇系列文章中我們使用的next()方法都是沒有傳參的,調用next()會依次返回迭代器里面的值。但是,實際上我們是可以給next()方法傳參數的,那在這種情況下我們會得到什么樣的結果呢?
function* createIterator() { let first = yield 1; console.log(`first: ${first}`); let second = yield first + 2; console.log(`second: ${second}`); let third = yield second + 3; } let iterator = createIterator(); console.log(iterator.next(0)); console.log(iterator.next(4)); console.log(iterator.next(5)); console.log(iterator.next());
我們得到下面的輸出結果:
{value: 1, done: false} first: 4 {value: 6, done: false} second: 5 {value: 8, done: false} {value: undefined, done: true}
在第二次和第三次的next調用中我們分別傳入參數4和5,而4和5也分別被賦值給了變量first和second。當我們執行:
iterator.next(4)的時候,生成器內部執行的代碼實際上是:
let first = 4; yield 4 + 2; //所以我們得到 {value: 6, done: false}
iterator.next(5)的時候,生成器內部執行的代碼實際上是:
let second = 5; yield 5 + 3; //所以我們得到 {value: 8, done: false}
看下面一個圖或許能更直觀一些:
以上截圖來自書 Understanding ECMAScript 6
但是上面的例子中,我們也看到一個有趣的現象,就是我們第一次調用next的時候,是傳了參數0的iterator.next(0),但是我們依然得到了結果{value: 1, done: false}。這是因為第一次調用next(),無論傳遞什么參數總是會被丟棄,所以給第一次調用的next()方法傳值是無意義的。
或許你看到這里也還不是完全明白了給next()傳參時,生成器內部到底是怎樣工作。接下來我們再看一個例子,這一次我們在第3次調用next()的時候,不傳參數,看會發生什么:
function* createIterator() { let first = yield 1; console.log(`first: ${first}`); let second = yield first + 2; console.log(`second: ${second}`); let third = yield second + 3; } let iterator = createIterator(); console.log(iterator.next(0)); console.log(iterator.next(4)); console.log(iterator.next()); console.log(iterator.next());
我們得到的輸出結果是:
{value: 1, done: false} first: 4 {value: 6, done: false} second: undefined {value: NaN, done: false} {value: undefined, done: true}
在第三次的next調用中,我們并沒有傳遞任何參數,生成器內部的執行情況就是:
let second; yield undefined + 2; //所以我們得到結果{value: NaN, done: false}
其實從這里例子我們也可以看出,在生成器內部,yield執行的結果并不會被保存下來賦值給內部的變量,例如這里我們在第三次沒有給next()傳遞參數,那么second的值就是undefined,而不是第二次yield執行結果的value 6。
2: 從迭代器中拋出錯誤
我們知道一般的函數的執行結果有2種:
1: 返回一個值 2: 拋出一個錯誤
生成器函數作為一種特殊的函數,但是它本身也是函數,所以它也可以拋出錯誤。只是它拋出錯誤的時間與一般函數不同,看一下下面的代碼:
function* createIterator() { let first = yield 1; let second = yield first + 2; yield second + 3; } let iterator = createIterator(); console.log(iterator.next()); //{value: 1, done: false} console.log(iterator.next(4)); //{value: 6, done: false} console.log(iterator.throw(new Error("Boom"))); //Uncaught Error: Boom
在生成器內部代碼執行情況如下圖所示:
以上截圖來自書 Understanding ECMAScript 6
當我們拋出錯誤之后,代碼就停止了。let second語句并不會被執行到。
但是生成器里面的throw()它會像yield一樣,也會返回一個結果。我們可以像一般函數一樣catch這個錯誤,并且之后的代碼依然可以得到執行:
function* createIterator() { let first = yield 1; let second; try { second = yield first + 2; } catch (error) { second = 6; } yield second + 3; } let iterator = createIterator(); console.log(iterator.next()); //{value: 1, done: false} console.log(iterator.next(4)); //{value: 6, done: false} console.log(iterator.throw(new Error("Boom"))); //{value: 9, done: false} console.log(iterator.next());//{value: undefined, done: true}
在這個例子中,我們catch了錯誤之后,給second賦值6,它后面的代碼yield second + 3;也依然可以得到執行。
3: 在生成器中使用return語句
生成器也是函數,所以它也可以使用return語句。只是由于生成器本身的特性,其內部的return的行為會和一般函數有些差別。我們先來看兩個例子,就能從中窺探一二:
例1:
function* createIterator() { yield 1; return; yield 2; } let iterator = createIterator(); console.log(iterator.next()); //{value: 1, done: false} console.log(iterator.next()); //{value: undefined, done: true} console.log(iterator.next());//{value: undefined, done: true}
例2:
function* createIterator() { yield 1; return 2; yield 3; } let iterator = createIterator(); console.log(iterator.next()); //{value: 1, done: false} console.log(iterator.next()); //{value: 2, done: true} console.log(iterator.next()); //{value: undefined, done: true}
上面的例1只是使用了return語句,然后后面沒有跟任何值,例2代碼就return了一個數字,我們從調用next()的結果可以看到:
1: return語句會終止返回迭代器里面本可以再迭代的值,會把done設置為false 2: return語句如果指定一個值,那么此次結果的value會被賦為此值;如果沒有指定,那value為undefined
4: 委托生成器(組合生成器或者生成器組合?)
單個的生成器函數里,yield后面往往跟一些我們常用的數據類型;但是,我們也可以yield 一個生成器函數,這樣的操作就叫委托生成器。先看一個代碼的例子:
function *createNumberIterator() { yield 1; yield 2; } function *createColorIterator() { yield "red"; yield "yellow"; } function *createCombinedIterator() { yield *createNumberIterator(); yield *createColorIterator(); } let combinedIterator = createCombinedIterator(); console.log(combinedIterator.next());//{value: 1, done: false} console.log(combinedIterator.next());//{value: 2, done: false} console.log(combinedIterator.next());//{value: "red", done: false} console.log(combinedIterator.next());//{value: "yellow", done: false} console.log(combinedIterator.next());//{value: undefined, done: true}
上面的這個示例,我們創建兩個不同的生成器函數createNumberIterator()和createColorIterator(),之后在createCombinedIterator()函數里通過yield語句調用前面的2個生成器函數,這樣createCombinedIterator()就成了一個擁有以上2個生成器的迭代器的生成器,調用*createCombinedIterator()的next(),就跟一般的生成器的next()方法的行為一樣。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/110287.html
摘要:我個人認為迭代器和生成器是新增的特性里面,非常重要的部分,充分地掌握和使用迭代器和生成器,是十分必要和重要的,所以我會寫關于二者的一系列文章。 我個人認為迭代器和生成器是es6新增的特性里面,非常重要的部分,充分地掌握和使用迭代器和生成器,是十分必要和重要的,所以我會寫關于二者的一系列文章。話不多說,先來了解一下基本概念:一:什么是迭代器 1: 迭代器是一個對象 2: 迭代器有一個屬性...
摘要:迭代器和生成器將迭代的概念直接帶入核心語言,并提供一種機制來自定義循環的行為。本文主要會介紹中新增的迭代器和生成器。屬性本身是函數,是當前數據結構默認的迭代器生成函數。 本文是 重溫基礎 系列文章的第十三篇。今日感受:每次自我年終總結,都會有各種情緒和收獲。 系列目錄: 【復習資料】ES6/ES7/ES8/ES9資料整理(個人整理) 【重溫基礎】1.語法和數據類型 【重溫基礎】2.流...
摘要:通過生成器創建的迭代器也是可迭代對象,因為生成器默認會為屬性賦值。我們可以用來訪問對象的默認迭代器,例如對于一個數組獲得了數組這個可迭代對象的默認迭代器,并操作它遍歷了數組中的元素。 ES6 新的數組方法、集合、for-of 循環、展開運算符(...)甚至異步編程都依賴于迭代器(Iterator )實現。本文會詳解 ES6 的迭代器與生成器,并進一步挖掘可迭代對象的內部原理與使用方法 ...
摘要:迭代器是一種特殊對象,每一個迭代器對象都有一個,該方法返回一個對象,包括和屬性。默認情況下定義的對象是不可迭代的,但是可以通過創建迭代器。在迭代器中拋出錯誤不再執行生成器返回語句生成器中添加表示退出操作。迭代器是一個對象。 迭代器(Iterator) ES5實現迭代器 迭代器是什么?遇到這種新的概念,莫慌張。 迭代器是一種特殊對象,每一個迭代器對象都有一個next(),該方法返回一個對...
閱讀 1565·2021-10-25 09:44
閱讀 2926·2021-09-04 16:48
閱讀 1543·2019-08-30 15:44
閱讀 2475·2019-08-30 15:44
閱讀 1731·2019-08-30 15:44
閱讀 2816·2019-08-30 14:14
閱讀 2964·2019-08-30 13:00
閱讀 2143·2019-08-30 11:09