摘要:在函數定義上使用關鍵字來表示方法調用時返回的值。是一個有屬性的。這個指向一個函數,這個函數返回關于這個對象的。在中所有的集合類對象和字符串都是,并且有自己默認的。注意本身是不返回任何值的,它只向外部產生值。
ES6新特性 iterators and Generators
ES6中引入了許多新特性,目前大量的JavaScript項目已經使用了ES6來進行開發,那么熟悉這些新的特性是十分必要的,例如Redux-Saga中大量的使用了Iterator和generator。這篇文章總結和介紹一下ES6中的Iterator和Generator。
iterators and Generators第一個問題什么是iterator?答案很簡單, Iterator是一個object,但是含有特定的接口,它有next method可以返回一個result object,這個result object有兩個屬性第一個是value,代表這個迭代的值, 第二個是done,代表迭代是否結束。如果我們自己來簡單實現一個Iterator,它是這樣的。
function createIterator(items) { var i = 0; return { next : function () { var done = i >= (items.length) var value = items[i++] return { done: done, value: value } } } } const items = [1,2,3] const iteratorA = createIterator(items) iteratorA.next() // {result:1, done: false}
那么Generator又是什么?Generator 是一個函數可以產生iterator。Generator函數用function關鍵字后邊帶*來表示。在函數定義上使用yield關鍵字來表示next方法調用時返回的值。例如
function *createIterator(){ yield 1; yield 2; yield 3; } let iterator = createIterator(); console.log(iterator.next().value); //1 console.log(iterator.next().value); //2 console.log(iterator.next().value); //3iterables
上邊介紹了什么是Iterator,什么是generator,下邊再介紹一個概念iterable。iterable是一個有Symbol.iterator屬性的object。這個symbol指向一個generator函數,這個函數返回關于這個對象的iterator。在ES6中所有的集合類對象(array, set, maps)和字符串都是iterable,并且有自己默認的iterator。當我們在使用 for-of時候實際上是利用了這些對象上的iterator,每次調用了next方法,將返回的result上的value返回回來。
let values = [1, 2, 3]; for (let num of values) { console.log(num); }
例如這段簡單的代碼,實際上調用了values上的iterator的next方法,將result上的value拿出來賦給num。既然是這樣我們可以采用這樣的方法來獲得默認的iterator。
let values = [1, 2, 3]; let iterator = values[Symbol.iterator]();
在ES6中對于集合類型的Object,其上定義了一些內置的iterator,分別是;
entries() - 返回一個返回key-value pair的iterator
values() - 返回一個返回collection對應值的iterator // chrome not supported
MDN
keys() - 返回一個返回collecttion對應key的iterator
以上就是iterator和generator的一些基本概念,下邊我們來看一下一些高階應用。
向iterator中傳遞參數上邊的例子中我們在調用iterator的next方法都是無參數調用的,但是我們同樣可以向next方法中傳遞參數。例如這樣。
function* createIterator() { let first = yield 1; let second = yield first + 2; yield second + 3; } let i= createItreator() i.next() // {value:1 done: false} i.next(5) // {value: 7 done: false} i.next(3) // {value: 6 done: false}
我們看上邊這個例子,在第二次調用中我們傳進去了5,返回值是7,這個傳進去的參數可以理解為上一次yield的返回值。注意yield本身是不返回任何值的,它只向外部產生值。如果我們查看yield在英語詞典中的意思,produce or generate (a result, gain, or financial return 所以yield的值是向外產生值。所以在第一次next后 first的值依舊是undefined。但是向next中傳遞參數,這個參數代表我們想要上一次yield在generator函數中的值。所以在第二次next后 返回值的value就是7(5+2)了。第三例子同理。所以基于上邊的原因我們向第一個next函數中傳入任何值都是沒有意義的。我們變化一下再看
function* createIterator() { yield 1; let first; let second = yield first + 2; yield second + 3; } i.next() // {value:1 done: false} i.next(5) // {value: NaN done: false} i.next(3) // {value: 6 done: false}
在第二個next中我們的返回是NaN, 為什么呢?這是因為first是Undefined,第一次的yield并沒有給first賦值。所以在yeild中的執行順序是每一次執行到相應的yield就完了,下次繼續向下執行。
在Iterator中Throw Error在iterator中我們可以來throw error 來達到控制執行的目的。例如上邊一個例子。
function* createIterator() { let first = yield 1; let second = yield first + 2; yield second + 3; } let i= createItreator() i.next() // {value:1 done: false} i.next(5) // {value: 7 done: false} i.throw(new Error("error")) // error thrown done is set to true after throw errorGenerator function中的Return
同樣在generator 我們可以使用 return來返回。
function* createIterator() { yield 1; return; yield 2; yield 3; } let iterator = createIterator(); console.log(iterator.next()); // "{ value: 1, done: false }" console.log(iterator.next()); // "{ value: undefined, done: true }"
第一次next后已經結束了所以 我們第二次next后done就已經是true了。
Generator 和 Iterator的應用實例:Task Runner我們可以使用generator和Iterator來實現一個task runner,可以讓我們不用手動的next,而是一次執行結束。代碼如下:
function run(taskDef) { let task = taskDef(); let value = task.next() function step() { if (!value.done) { value = task.next(value.value) step() } } step() } run(function*(){ let first = yield 1; let second = yield first + 3; yield second + 4; })
上邊就是一個例子,這樣定義的run function就可以順序執行這些generator定義的步驟。
實際上generator和Iterator最為實際的作用是可以控制異步函數的執行,下邊我們可以簡單的例子。
function run(taskDef) { let task = taskDef(); let result = task.next() function step() { if (!result.done) { if (typeof result.value === "function") { result.value(function(err, data) { if (err) { console.log("err", err); task.throw(err) return } console.log("err", data); result = task.next(data); step() }) } else { result = task.next(result.value) step() } } } step() } let fs = require("fs"); function readFile(filename) { return function (callback) { fs.readFile(filename, callback); }; } run(function* () { let contents = yield readFile("abc.json"); console.log(contents); console.log("Done"); });
首先我們定義了一個task runner run function 在其中當發現result中的value是function的時候,就執行這個function, 并且在異步函數的callback中,當沒有error的時候執行下一步。
在看我們的ReadFile function,fs模塊中的readFile是一個異步的函數,而在這里我們將其進行了封裝成為一個新的函數。讓其返回一個function給在task runner中使用。那么在我們的generator函數中,我們看上去的代碼就和同步的一樣了,先readfile,完成后將其輸出。這樣使用Iterator和generator可以幫助我們寫出一個比較好看的異步執行函數。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/83219.html
摘要:下例實現了一個數組的迭代器在中,可迭代數據結構比如數組都必須實現一個名為的方法,該方法返回一個該結構元素的迭代器。原話是還可以傳遞返回值。 前記 按照規劃,明年年中,ECMAScript 6(ES6)就要正式發布了。 最近抽空看了Dr. Axel Rauschmayer的幾篇文章和演講PPT,對新特性有了些了解。 趁沒忘,抓緊記錄下,夾雜自己的感受。 計劃分三部分: 新語法...
摘要:字面上是生成器的意思,在里是迭代器生成器,用于生成一個迭代器對象。當執行的時候,并不執行函數體,而是返回一個迭代器。迭代器具有方法,每次調用方法,函數就執行到語句的地方。也有觀點極力反對,認為隱藏了本身原型鏈的語言特性,使其更難理解。 本文為 ES6 系列的第一篇。旨在給新同學一些指引,帶大家走近 ES6 新特性。簡要介紹: 什么是 ES6 它有哪些明星特性 它可以運行在哪些環境 ...
摘要:目前的標準化工作正在進行中,預計會在年月份放出正式敲定的版本。反的方法可以接收一個參數并且返回值取決與它的構造函數。之后就可以用這個返回值做為對象的鍵了。 本文基于lukehoban/es6features ,同時參考了大量博客資料,具體見文末引用。 ES6(ECMAScript 6)是即將到來的新版本JavaScript語言的標準,代號harmony(和諧之意,顯然沒有跟上我國的步伐...
摘要:生成器函數是的新特性,它允許一個函數返回的可遍歷對象生成多個值。在使用中你會看到語法和一個新的關鍵詞我們在之前有認識迭代器主要解決我們的數組遍歷方法,主要解決數組遍歷,提高了性能。 generators(生成器) Generator 函數是 ES6 的新特性,它允許一個函數返回的可遍歷對象生成多個值。 在使用中你會看到 * 語法和一個新的關鍵詞 yield: 我們在之前有認識itera...
摘要:它們都用于聲明變量。盲目使用替換后可能會導致預期意外的結果。有鑒于此,還是建議使用字符串,布爾和數字類型的數據類型。像使用這種下劃線命名約定在一個開源項目中,命名規則很難維持得一直很好,這樣經常會造成一些困擾。 今天群里有小伙伴跟我聊天,問了我幾個關于ES6的問題,我才意識到,大部分初學者在學習的過程中,都是學了HTML/CSS/JS之后就開始上手學習框架了,而對于ES6的重視程度卻不...
閱讀 2436·2019-08-30 15:52
閱讀 2237·2019-08-30 12:51
閱讀 2833·2019-08-29 18:41
閱讀 2812·2019-08-29 17:04
閱讀 811·2019-08-29 15:11
閱讀 1720·2019-08-28 18:02
閱讀 3603·2019-08-26 10:22
閱讀 2510·2019-08-26 10:12