国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

ES6 之 Iterator&Generator

xietao3 / 1608人閱讀

摘要:可迭代對象就具有屬性,它是一種與迭代器密切相關(guān)的對象。它通過指定的函數(shù)可以返回一個作用于附屬對象的迭代器。迭代器特點每次調(diào)用方法時,返回一個數(shù)組,數(shù)組中兩個元素,分別表示鍵和值。示例之輸出輸出輸出之迭代器特點返回集合中存在的每一個鍵。

Iterator由來

不推薦Iterator方法。 Iterator 函數(shù)是一個 SpiderMonkey 專有特性,并且會在某一時刻被刪除。
有一點,需要清楚的,就是“迭代協(xié)議”。迭代協(xié)議MDN說明

// 簡單示例,摘自“深入理解ES6”
function createIterator(items) {
    let i = 0;
    
    return {
        next: function() {
            let done = (i >= items.length);
            let value = !done ? items[i++] : undefined;
            
            return {
                done,
                value
            }
        }
    }
}
let iterator = createIterator([1, 2, 3]);

console.log(iterator.next()); // { done: false, value: 1 }
console.log(iterator.next()); // { done: false, value: 2 }
console.log(iterator.next()); // { done: false, value: 3 }
console.log(iterator.next()); // { done: true, value: undefined }
// 之后所有的調(diào)用都會返回相同的內(nèi)容
console.log(iterator.next()); // { done: true, value: undefined }
Generator定義

生成器是一種返回迭代器的函數(shù),通過function關(guān)鍵字后的星號(*)來表示,函數(shù)中會用到新的關(guān)鍵字yield。星號可以緊挨著function關(guān)鍵字,也可以在中間加一個空格。

function *createIterator() {
    yield 1;
    yield 2;
    yield 3;
}
let iterator = createIterator();
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: undefined, done: true }

// 換個方法
function *createIterator(items) {
    for (let i = 0; i < items.length; i++) {
        yield items[i];
    }
}

let iterator = createIterator([1, 2, 3]);
// iterator 與前面代碼創(chuàng)建的 iterator 功能一樣,可以試一下。
yield的使用限制
yield關(guān)鍵字只能在生成器內(nèi)部使用,在其他地方使用會導(dǎo)致程序拋出語法錯誤,即便在生成器的函數(shù)里使用也如此。
function *createIterator(items) {
    items.forEach(function(item) {
        yield item + 1;
    });
}
// 會報語法錯誤 node ./iterator.js

從字面理解,yield關(guān)鍵字確定在createIterator()函數(shù)內(nèi)部,但是它與return關(guān)鍵字一樣,二者都不能穿透函數(shù)邊界。嵌套函數(shù)中的return語句不能用作函數(shù)的返回語句,而此處嵌套函數(shù)中的yield語句會導(dǎo)致程序拋出語法錯誤。
生成器函數(shù)表達式&對象方法
通過上面的方法,關(guān)于函數(shù)表達式和對象方法,直接上代碼吧,更明白。

// 函數(shù)表達式
let createIterator = function *(items) {
    for (let i =0; i < items.length; i++) {
        yield items[i];
    }
}

let iterator = createIterator([1, 2, 3]);

// 對象方法
let o = {
    createIterator: function *(items) {
        yield items[i];
    }
}

let iterator = o.createIterator([1, 2, 3]);
可迭代對象 & for-of 循環(huán)

看過Symbol文章的小伙伴應(yīng)該都知道,Symbol.iterator就是 well-known Symbol之一??傻鷮ο缶途哂蠸ymbol.iterator屬性,它是一種與迭代器密切相關(guān)的對象。它通過指定的函數(shù)可以返回一個作用于附屬對象的迭代器。在ES6中,所有的集合對象(Array, Set, Map)和字符串都是可迭代對象,這些對象中都有默認的迭代器。當然,ES中也添加了for-of循環(huán)這些可迭代對象。

迭代器

for-of循環(huán)

這是解決循環(huán)內(nèi)部索引跟蹤問題的關(guān)鍵工具。
for-of循環(huán)每執(zhí)行一次都會調(diào)用可迭代對象中的next()方法,并將迭代器返回的結(jié)果對象的value屬性存儲在一個變量中,循環(huán)將持續(xù)執(zhí)行這一過程直到返回對象的done屬性為true。

let values = [1, 2, 3];
for (let num of values) {
    console.log(num);
}
// 輸出:
// 1
// 2
// 3

示例說明:
for-of循環(huán)的代碼通過調(diào)用values數(shù)組的Symbol.iterator方法來獲取迭代器,這一過程是在Javascript引擎背后完成的。隨后迭代器的next()的方法被多次調(diào)用,從其返回對象的value屬性讀取值并存儲在變量num中,直到對象的done為true時循環(huán)退出,所以num不會賦值為undefined

訪問默認迭代器

從上面的例子可以看出,可迭代對象都有一個默認迭代器。這個迭代器可通過Symbol.iterator來訪問。

let values = [1, 2, 3];
let iterator = values[Symbol.iterator]();
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: undefined, done: true }

由此,我們可以判斷對象是否可迭代,是不是有更好的方法?

function isIterator(object) {
    return typeof object[Symbol.iterator] === "function";
}

console.log(isIterator([1, 2, 3]));  // true
console.log(isIterator("Hello"));  // true
console.log(isIterator(new Map()));  // true
console.log(isIterator(new Set()));  // true
console.log(isIterator(new WeakMap()));  // false
console.log(isIterator(new WeakSet()));  // false
創(chuàng)建可迭代對象

默認情況下,開發(fā)者定義的對象都是不可迭代的對象,但如果給Symbol.iterator屬性添加一個生成器,則可以將其變?yōu)榭傻鷮ο蟆?/p>

let collection = {
    items: [],
    *[Symbol.iterator]() {
        for (let item of this.items) {
            yield item;
        }
    }
};

collection.items.push(1);
collection.items.push(2);
collection.items.push(3);

for (let item of collection){
    console.log(item);
}
// 輸出:
// 1
// 2
// 3
內(nèi)建迭代器

到這里,應(yīng)該明白,ES6中已經(jīng)默認為很多內(nèi)建類型提供了內(nèi)建迭代器,只有這些內(nèi)容無法實現(xiàn)目標時,才需要自己創(chuàng)建。ES6中有三種集合對象: 數(shù)組、Map與Set集合,他們內(nèi)建了以下三種迭代器:

entries() 返回值為多個鍵值對迭代器

values() 返回值為集合的迭代器

keys() 返回集合中所有鍵名迭代器

MDN 關(guān)于內(nèi)建迭代器 說的比較簡單,我就按“深入理解ES6”來詳細說一下吧。

entries() 迭代器

特點:每次調(diào)用next()方法時,entries()返回一個數(shù)組,數(shù)組中兩個元素,分別表示鍵和值。

- Array 第一個元素為數(shù)字類型的索引,第二個元素為值
- Set 第一個元素與第二個元素都是值,因為Set中值也作為鍵來使用
- Map 第一個元素為鍵,第二個元素為值
示例:
let colors = [ "red", "green", "blue"];
let tracking = new Set([ 123, 456, 890]);
let data = new Map();
data.set("title", "ES6之Iterator&Generator");
data.set("formate", "net share");

for (let entry of colors.entries()) {
    console.log(entry);
}
// 輸出:
// [ 0, "red" ]
// [ 1, "green" ]
// [ 2, "blue" ]

for (let entry of tracking.entries()) {
    console.log(entry);
}
// 輸出:
// [ 123, 123 ]
// [ 456, 456 ]
// [ 890, 890 ]

for (let entry of data.entries()) {
    console.log(entry);
}
// 輸出:
// [ "title", "ES6之Iterator&Generator" ]
// [ "formate", "net share" ]
values() 迭代器

特點: 返回集合中所存的所有值。
示例:

let colors = [ "red", "green", "blue"];
let tracking = new Set([ 123, 456, 890]);
let data = new Map();
data.set("title", "ES6之Iterator&Generator");
data.set("formate", "net share");

for (let entry of colors.values()) {
    console.log(entry);
}
// 輸出:
// red
// green
// blue

for (let entry of tracking.values()) {
    console.log(entry);
}
// 輸出:
// 123
// 456 
// 890 

for (let entry of data.values()) {
    console.log(entry);
}
// 輸出:
// ES6之Iterator&Generator
// net share
keys() 迭代器

特點:返回集合中存在的每一個鍵。
示例:

    let colors = [ "red", "green", "blue"];
    let tracking = new Set([ 123, 456, 890]);
    let data = new Map();
    data.set("title", "ES6之Iterator&Generator");
    data.set("formate", "net share");
    
    for (let entry of colors.keys()) {
        console.log(entry);
    }
    // 輸出:
    // 0
    // 1
    // 2
    
    for (let entry of tracking.keys()) {
        console.log(entry);
    }
    // 輸出:
    // 123
    // 456
    // 890
    
    for (let entry of data.keys()) {
        console.log(entry);
    }
    // 輸出:
    // title
    // formate

不同集合,會使用不同的默認迭代器,Array和Set使用的是values()迭代器,而Map則使用的是entries()迭代器。

string 迭代器

特點: 與Array類似。string也可以通過下標訪問字符內(nèi)容。由于下標操作是編碼單元而非字符,所以無法訪問雙字節(jié)符。在Unicode支持不好的版本(node或瀏覽器引擎),會出現(xiàn)錯誤。如果使用for-of,則不會出現(xiàn)這種問題,因為其操作的是字符而非編碼單元。
思考一個問題:展開運算符與非數(shù)組可迭代對象
如果對可迭代對象使用展開運算,會調(diào)用默認迭代器嗎?返回又是什么呢?
非數(shù)組可迭代對象呢?
示例:

let o = {
    a: "aaaa",
    b: 123,
    c: "ffffd",
    *[Symbol.iterator]() {
        yield this.a;
        yield this.b;
        yield this.c;
    }
}

let ar = [...o];
console.log(ar);
for(let item of ar) {
    console.log(item);
}
// 輸出
// [ "aaaa", 123, "ffffd" ]
// aaaa
// 123
// ffffd
迭代器高級功能 給迭代器傳參

這次先做示例,再做說明。
示例1:

function *createIterator() {
    let first = yield 1;
    let second = yield first + 2;
    yield second + 3;
}

let iterator = createIterator();
 console.log(iterator.next());
 console.log(iterator.next(4));
 console.log(iterator.next(6));
 console.log(iterator.next());
// 輸出:
// { value: 1, done: false }
// { value: 6, done: false }
// { value: 9, done: false }
// { value: undefined, done: true }

示例2:

function *createIterator() {
    let first = yield 1;
    let second = yield first + 2;
    yield first + 3;
}

let iterator = createIterator();
 console.log(iterator.next());
 console.log(iterator.next(4));
 console.log(iterator.next(6));
 console.log(iterator.next());
// 輸出:
// { value: 1, done: false }
// { value: 6, done: false }
// { value: 7, done: false }
// { value: undefined, done: true }

示例3:

function *createIterator() {
    let first = yield 1;
    let second = yield first + 2;
    yield second + 3;
}

let iterator = createIterator();
 console.log(iterator.next(5));
 console.log(iterator.next(4));
 console.log(iterator.next(6));
 console.log(iterator.next());
// 輸出:
// { value: 1, done: false }
// { value: 6, done: false }
// { value: 9, done: false }
// { value: undefined, done: true }

示例4

function *createIterator() {
    let first = 1;
    yield first;
    let second = yield first + 2;
    yield second + 3;
}

let iterator = createIterator();
 console.log(iterator.next(5));
 console.log(iterator.next(4));
 console.log(iterator.next(6));
 console.log(iterator.next());
// 示例:
// { value: 1, done: false }
// { value: 3, done: false }
// { value: 9, done: false }
// { value: undefined, done: true }

示例5:

function *createIterator() {
    let first = yield 1;
    let second = yield first + 2;
    yield second + 3;
}

let iterator = createIterator();
 console.log(iterator.next());
 console.log(iterator.next());
 console.log(iterator.next());
 console.log(iterator.next());
// 輸出:
// { value: 1, done: false }
// { value: NaN, done: false }
// { value: NaN, done: false }
// { value: undefined, done: true }

示例5的輸出結(jié)果,是不是很意外?yield返回變量與正常變量賦值有何不同?
分析:

傳遞參數(shù)會替代上一次yield的返回值

第一個next()執(zhí)行,傳參無效。因為第一次調(diào)用yield時,之前沒有任何yield語句執(zhí)行

非yield返回值 ,不受next()參數(shù)影響

在一個含參的yield語句中,表達式右側(cè)等價于第一次調(diào)用next()方法后下一個返回值。表達式左側(cè)等價于第二次調(diào)用next()方法后,在函數(shù)繼續(xù)執(zhí)行前得到的返回值。

拋出錯誤

這個也先示例,后說明。
示例1:

function *createIterator() {
    let first = yield 1;
    let second = yield first + 2;
    yield second + 3;
}

let iterator = createIterator();
 console.log(iterator.next());
 console.log(iterator.next(4));
 console.log(iterator.throw(new Error("Boom")));
 console.log(iterator.next(5));
// 輸出:
// { value: 1, done: false }
// { value: 6, done: false }
// xx/iterator.js:146
//    let second = yield first + 2;
//                 ^
//
// Error: Boom

分析:前兩個表達式正常求值,在繼續(xù)執(zhí)行l(wèi)et second 求值前,錯誤就會被拋出,并阻止了代碼繼續(xù)執(zhí)行。
這個過程,與直接拋出異常很相似,只是拋出的時機不同。
示例2

function *createIterator() {
    let first = yield 1;
    let second ;
    try {
        second = yield first + 2;
    } catch (ex){
        second = 6;
    }
    yield second + 3;
}

let iterator = createIterator();
 console.log(iterator.next());
 console.log(iterator.next(4));
 console.log(iterator.throw(new Error("Boom")));
 console.log(iterator.next(5));

// 輸出:
// { value: 1, done: false }
// { value: 6, done: false }
// { value: 9, done: false }
// { value: undefined, done: true }

分析:
用try...catch語句來捕獲異常,包裹著第二名語句。盡管這條語句本身沒有錯誤,但在給second賦值前,還是會拋出錯誤,catch代碼塊捕捉到這個錯誤后,并把second = 6. 下一條yield語句繼續(xù)執(zhí)行后,返回9.

返回語句

基本上兩個示例可以概括。
示例1

function *createIterator() {
    yield 1;
    return;
    yield 2;
    yield 3;
}

let iterator = createIterator();
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
// 輸出:
// { value: 1, done: false }
// { value: undefined, done: true }
// { value: undefined, done: true }

示例2

function *createIterator() {
    yield 1;
    return 33;
    yield 2;
    yield 3;
}

let iterator = createIterator();
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
// 輸出:
// { value: 1, done: false }
// { value: 33, done: true }
// { value: undefined, done: true }
委托生成

先看三個示例吧,這個只是語法規(guī)范。
示例1

function *createNumIterator() {
    yield 1;
    yield 2;
}

function *createColorIterator() {
    yield "red";
    yield "green";
}

function *createCombinedIterator() {
    yield *createNumIterator();
    yield *createColorIterator();
    yield true;
}

var iterator = createCombinedIterator();

console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());

// 輸出:
// { value: 1, done: false }
// { value: 2, done: false }
// { value: "red", done: false }
// { value: "green", done: false }
// { value: true, done: false }
// { value: undefined, done: true }

分析:語法規(guī)范,多個迭代器合并,可以創(chuàng)建一個生成器,再給yield語句添加一個號,就可以將生成數(shù)據(jù)的過程委托給其他迭代器。當定義這些生成器時,只需要將號放置在關(guān)鍵字yield和生成器的函數(shù)名之間即可。
示例2

function *createNumIterator() {
    yield 1;
    yield 2;
    return 3;
}

function *createRepeatIterator(count) {
    for (let i = 0; i < count; i++){
        yield "repeat";
    }
}

function *createCombinedIterator() {
    let result = yield *createNumIterator();
    yield *createRepeatIterator(result);
}

var iterator = createCombinedIterator();

console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
// 輸出 :
// { value: 1, done: false }
// { value: 2, done: false }
// { value: "repeat", done: false }
// { value: "repeat", done: false }
// { value: "repeat", done: false }
// { value: undefined, done: true }

分析:執(zhí)行過程,先被委托給了createNumIterator(),返回值會被賦給變量result,執(zhí)行到return 3時,返回精數(shù)值3。這個值隨后被傳入createRepeatIterator()方法。
但是,無論通過何種方式調(diào)用next()方法,數(shù)值3永遠不會被返回,它只存在于createCombinedIterator()的內(nèi)部。如果要輸出3,參看示例3。
示例3

function *createNumIterator() {
    yield 1;
    yield 2;
    return 3;
}

function *createRepeatIterator(count) {
    for (let i = 0; i < count; i++){
        yield "repeat";
    }
}

function *createCombinedIterator() {
    let result = yield *createNumIterator();
    yield result;
    yield *createRepeatIterator(result);
}

var iterator = createCombinedIterator();

console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
// 輸出:
// { value: 1, done: false }
// { value: 2, done: false }
// { value: 3, done: false }
// { value: "repeat", done: false }
// { value: "repeat", done: false }
// { value: "repeat", done: false }
// { value: undefined, done: true }

期待的3,出來了。

異步任務(wù)執(zhí)行

生成器支持在函數(shù)中暫停代碼執(zhí)行,可以挖掘異步處理的更多方法。

簡單任務(wù)執(zhí)行器

示例:

function run(taskDef) {

    // 創(chuàng)建迭代器
    let task = taskDef();
    // 開始執(zhí)行任務(wù)
    let result = task.next();

    function step() {
        if (!result.done) {
            result = task.next();
            step();
        }
    }

    step();
}

run(function *() {
    console.log(1);
    yield;
    console.log(2);
    yield;
    console.log(3);
    yield;
});

分析:

函數(shù)run()接受一個生成器作為參數(shù),這個函數(shù)定義了后續(xù)要執(zhí)行的任務(wù),生成一個迭代器并將它存儲在變量task中。

首次調(diào)用next(),返回的結(jié)果被存儲起來,稍后繼續(xù)使用。

step()函數(shù)檢查result.done的值,false時,繼續(xù)執(zhí)行next()方法,并執(zhí)行step()操作。

每次執(zhí)行next()返回值會覆蓋變量result原來的值

傳參

示例:

function run(taskDef) {

    // 創(chuàng)建迭代器
    let task = taskDef();
    // 開始執(zhí)行任務(wù)
    let result = task.next();

    function step() {
        if (!result.done) {
            result = task.next(result.value);
            step();
        }
    }

    step();
}

run(function *() {
   let value = yield 1;
   console.log(value);

   value = yield value + 3;
   console.log(value);
});

注意yield表達式求值。

異步

示例:

// redux-saga 經(jīng)典應(yīng)用

redux-saga
Iterator&Generator 之 MDN 說明

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/105636.html

相關(guān)文章

  • ES6&amp;ES7中的異步Generator的語法

    摘要:第二次同理,遇到了第二個函數(shù)會停下來,輸出的遍歷器對象值為,的值依然是。比如返回的遍歷器對象,都會有一個方法,這個方法掛在原型上。這三個函數(shù)共同的作用是讓函數(shù)恢復(fù)執(zhí)行。 Generator的語法 generator的英文意思是生成器 簡介 關(guān)于Generator函數(shù),我們可以理解成是一個狀態(tài)機,里面封裝了多種不同的狀態(tài)。 function* gener(){ yield hel...

    djfml 評論0 收藏0
  • ES6&amp;ES7中的異步async函數(shù)

    摘要:更好的語義和分別表示異步和等待,比起和更容易理解。前邊聲明關(guān)鍵字,表示內(nèi)部有內(nèi)部操作,調(diào)用函數(shù)會返回一個對象。等價于其中函數(shù)就是自動執(zhí)行器。 async函數(shù) 定義 async函數(shù)其實就是之前說過的Generator的語法糖,用于實現(xiàn)異步操作。它是ES2017的新標準。 讀取兩個文件: const fs = require(fs) const readFile = function(f...

    dongxiawu 評論0 收藏0
  • ES6Iterator、Generator

    摘要:舉個例子遍歷器生成函數(shù),作用就是返回一個遍歷器對象,方法返回一個對象,表示當前數(shù)據(jù)成員的信息。該對象本身也具有屬性,執(zhí)行后返回自身。 Iterator的作用 一是為各種數(shù)據(jù)結(jié)構(gòu),提供一個統(tǒng)一的、簡便的訪問接口;(統(tǒng)一)二是使得數(shù)據(jù)結(jié)構(gòu)的成員能夠按某種次序排列;(按序)三是ES6創(chuàng)造了一種新的遍歷命令for...of循環(huán),Iterator接口主要供for...of消費。舉個例子:遍歷器生...

    tuomao 評論0 收藏0
  • ES6IteratorGenerator

    摘要:舉個例子遍歷器生成函數(shù),作用就是返回一個遍歷器對象,方法返回一個對象,表示當前數(shù)據(jù)成員的信息。該對象本身也具有屬性,執(zhí)行后返回自身。 Iterator的作用 一是為各種數(shù)據(jù)結(jié)構(gòu),提供一個統(tǒng)一的、簡便的訪問接口;(統(tǒng)一)二是使得數(shù)據(jù)結(jié)構(gòu)的成員能夠按某種次序排列;(按序)三是ES6創(chuàng)造了一種新的遍歷命令for...of循環(huán),Iterator接口主要供for...of消費。舉個例子:遍歷器生...

    ashe 評論0 收藏0

發(fā)表評論

0條評論

xietao3

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<