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

資訊專欄INFORMATION COLUMN

【JS基礎(chǔ)】從JavaScript中的for...of說起(上) - iterator 和 gene

wslongchen / 2936人閱讀

摘要:當(dāng)這個(gè)迭代器的方法被首次后續(xù)調(diào)用時(shí),其內(nèi)的語句會(huì)執(zhí)行到第一個(gè)后續(xù)出現(xiàn)的位置為止,后緊跟迭代器要返回的值。在這個(gè)回調(diào)函數(shù)里,我們使用第一個(gè)請(qǐng)求返回的,再次發(fā)起一個(gè)請(qǐng)求。

寫在前面
本文首發(fā)于公眾號(hào):符合預(yù)期的CoyPan

后續(xù)文章:【JS基礎(chǔ)】從JavaScript中的for...of說起(下) - async和await

先來看一段很常見的代碼:

const arr = [1, 2, 3];
for(const i of arr) {
    console.log(i); // 1,2,3
}

上面的代碼中,用for...of來遍歷一個(gè)數(shù)組。其實(shí)這里說遍歷不太準(zhǔn)確,應(yīng)該是說:for...of語句在可迭代對(duì)象(包括 Array,Map,Set,String,TypedArray,arguments 對(duì)象等等)上創(chuàng)建一個(gè)迭代循環(huán),調(diào)用自定義迭代鉤子,并為每個(gè)不同屬性的值執(zhí)行語句。

iterator

ECMAScript 2015規(guī)定了關(guān)于迭代的協(xié)議,這些協(xié)議可以被任何遵循某些約定的對(duì)象來實(shí)現(xiàn)。如果一個(gè)js對(duì)象想要能被迭代,那么這個(gè)對(duì)象或者其原型鏈對(duì)象必須要有一個(gè)Symbol.iterator的屬性,這個(gè)屬性的值是一個(gè)無參函數(shù),返回一個(gè)符合迭代器協(xié)議的對(duì)象。這樣的對(duì)象被稱為符合【可迭代協(xié)議】。

typeof Array.prototype[Symbol.iterator] === "function"; // true
typeof Array.prototype[Symbol.iterator]() === "object"; // true

數(shù)組之所以可以被for...of迭代,就是因?yàn)閿?shù)組的原型對(duì)象上擁有Symbol.iterator屬性,這個(gè)屬性返回了一個(gè)符合【迭代器協(xié)議】的對(duì)象。

一個(gè)符合【迭代器協(xié)議】的對(duì)象必須要有一個(gè)next屬性,next屬性也是一個(gè)無參函數(shù),返回一個(gè)對(duì)象,這個(gè)對(duì)象至少需要有兩個(gè)屬性:done, value, 大概長(zhǎng)成下面這樣:

{
    next: function(){
        return {
            done: boolean, // 布爾值,表示迭代是否完成,如果沒有這個(gè)屬性,則默認(rèn)為false
            value: any // 迭代器返回的任何javascript值。如果迭代已經(jīng)完成,value屬性可以被省略
        }
    }
}

依舊來看一下數(shù)組:

typeof Array.prototype[Symbol.iterator]().next === "function" // true
Array.prototype[Symbol.iterator]().next() // {value: undefined, done: true}

const iteratorObj = [1,2,3][Symbol.iterator]();
iteratorObj.next(); // { value: 1, done: false }
iteratorObj.next(); // { value: 2, done: false }
iteratorObj.next(); // { value: 3, done: false }
iteratorObj.next(); // { value: undefined, done: true }

我們自己來實(shí)現(xiàn)一個(gè)可以迭代的對(duì)象。

const myIterator = {
    [Symbol.iterator]: function() {
        return {
            i: 0,
            next: function() {
                if(this.i < 2) {
                    return { value: this.i++ , done: false };
                } else {
                    return { done: true };
                }
            }
        }
    }
}
for(const item of myIterator) {
    console.log(item);
}

// 0
// 1

不光for...of會(huì)使用對(duì)象的iterator接口,下面這些用法也會(huì)默認(rèn)使用對(duì)象的iteretor接口。
(1) 解構(gòu)賦值 (2) 擴(kuò)展運(yùn)算符 (3) yield*

generator 生成器對(duì)象和生成器函數(shù)

generator表示一個(gè)生成器對(duì)象。這個(gè)對(duì)象符合【可迭代協(xié)議】和【迭代器協(xié)議】,是由生成器函數(shù)(generator function)返回的。

什么是生成器函數(shù)呢?MDN上的描述如下:

生成器函數(shù)在執(zhí)行時(shí)能暫停,后面又能從暫停處繼續(xù)執(zhí)行。
調(diào)用一個(gè)生成器函數(shù)并不會(huì)馬上執(zhí)行它里面的語句,而是返回一個(gè)這個(gè)生成器的 迭代器 (iterator )對(duì)象。當(dāng)這個(gè)迭代器的 next() 方法被首次(后續(xù))調(diào)用時(shí),其內(nèi)的語句會(huì)執(zhí)行到第一個(gè)(后續(xù))出現(xiàn)yield的位置為止,yield 后緊跟迭代器要返回的值。或者如果用的是 yield*(多了個(gè)星號(hào)),則表示將執(zhí)行權(quán)移交給另一個(gè)生成器函數(shù)(當(dāng)前生成器暫停執(zhí)行)。next()方法返回一個(gè)對(duì)象,這個(gè)對(duì)象包含兩個(gè)屬性:value 和 done,value 屬性表示本次 yield 表達(dá)式的返回值,done 屬性為布爾類型,表示生成器后續(xù)是否還有 yield 語句,即生成器函數(shù)是否已經(jīng)執(zhí)行完畢并返回。

看下面的例子:

function* gen() { // gen一個(gè)生成器函數(shù)
  yield 1;
  yield 2;
  yield 3;
}
const g = gen(); // g是一個(gè)生成器對(duì)象,是可迭代的
Object.prototype.toString.call(g) === "[object Generator]" // true
g.next(); // { value: 1, done: false }
g.next(); // { value: 2, done: false }
g.next(); // { value: 3, done: false }
g.next(); // { value: undefined, done: true }

因?yàn)樯善鲗?duì)象符合可迭代協(xié)議和迭代器協(xié)議,我們可以用for...of來進(jìn)行迭代。for…of會(huì)拿到迭代器返回值的value,也就是說,在迭代generator時(shí),for…of拿到的是yield后面緊跟的那個(gè)值。

function* gen2() {
    yield "a";
    yield "b";
    yield "c";
}
const g2 = gen2();
for(const i of g2) {
    console.log(i);
}
// a
// b
// c
生成器函數(shù)的"嵌套"
function *gen1(i) {
    yield i+1;
    yield i+2;
    yield *gen2(i+2); // 將執(zhí)行權(quán)移交給gen2
    yield i+3;
}

function *gen2(i) {
    yield i*2;
}

const g = gen1(0);
g.next(); // { value: 1, done: false }
g.next(); // { value: 2, done: false } 
g.next(); // { value: 4, done: false }
g.next(); // { value: 3, done: false }
g.next(); // { value: undefined, done: true }
生成器函數(shù)里的參數(shù)傳遞
function* gen3() {
    let a = yield 1;
    console.log("a:", a); 
    let b = yield a + 1;
    yield b + 10;
}
const g = gen3();
g.next(); // { value: 1, done: false } 這個(gè)時(shí)候,代碼執(zhí)行到gen3里第一行等號(hào)右邊
g.next(100); // a: 100 , { value: 101, done: false }。代碼執(zhí)行第一行等號(hào)的左邊,我們傳入了100,這個(gè)100會(huì)作為a的值,接著執(zhí)行第二行的log, 然后執(zhí)行到第三行等號(hào)的右邊。
g.next(); // { value: NaN, done: false }。代碼執(zhí)行第三行等號(hào)的左半部分,由于我們沒有傳值,b就是undefined, undefined + 10 就是NaN了。
g.next(); // { value: undefined, done: true }

如果我們使用for...of來遍歷上述的生成器對(duì)象,由于for…of拿到的是迭代器返回值的value,所以會(huì)得到以下的結(jié)果:

function* gen4() {
    let a = yield 1;
    let b = yield a + 1;
    yield b + 10;
}
const g4 = gen4();
for(const i of g4) {
    console.log(i);
}
// 1
// NaN
// NaN

下面是一個(gè)使用generator和for...of輸出斐波拉契數(shù)列的經(jīng)典例子:

function* fibonacci() {
    let [prev, curr] = [0, 1];
    while(1){
        [prev, curr] = [curr, prev + curr];
        yield curr;
    }
}
for (let n of fibonacci()) {
    if (n > 100) {
        break
    }
    console.log(n);
}

稍微總結(jié)一下,generator給了我們控制暫停代碼執(zhí)行的能力,我們可以自己來控制代碼執(zhí)行。那是否可以用generator來寫異步操作呢 ?

iterator,generator與異步操作

一個(gè)很常見的場(chǎng)景: 頁面發(fā)起一個(gè)ajax請(qǐng)求,請(qǐng)求返回后,執(zhí)行一個(gè)回調(diào)函數(shù)。在這個(gè)回調(diào)函數(shù)里,我們使用第一個(gè)請(qǐng)求返回的url,再次發(fā)起一個(gè)ajax請(qǐng)求。(這里先不考慮使用Promise)

// 我們先定義發(fā)起ajax的函數(shù),這里用setTimeout模擬一下
function myAjax(url, cb) {
    setTimeout(function(){
        const data = "ajax返回了";
        cb && cb(resData);
    }, 1000);
}

// 一般情況下,要實(shí)現(xiàn)需求,一般可以這樣寫
myAjax("https://xxxx", function(url){
    myAjax(url, function(data){
        console.log(data);
    });
});

我們嘗試用generator的寫法來實(shí)現(xiàn)上面的需求.

// 先把a(bǔ)jax函數(shù)改造一下, 把url提出來作為一個(gè)參數(shù),然后返回一個(gè)只接受回調(diào)函數(shù)作為參數(shù)的newAjax函數(shù)
// 這種只接受回調(diào)函數(shù)作為參數(shù)的函數(shù)被稱為thunk函數(shù)。
function thunkAjax(url) {
    return function newAjax(cb){
        myAjax(url, cb);
    }
}

// 我們定義一個(gè)generator function
function* gen() {
    const res1 = yield thunkAjax("http://url1.xxxx");
    console.log("res1", res1);
    const res2 = yield thunkAjax(res1);
    console.log("res2", res2);
}

// 實(shí)現(xiàn)需求。
const g = gen();
const y1 = g.next(); // y1 = { value: ?, done: false }. 這里的value,就是一個(gè)newAjax函數(shù),接受一個(gè)回調(diào)函數(shù)作為參數(shù)
y1.value(url => {  // 執(zhí)行y1.value這個(gè)函數(shù),并且傳入了一個(gè)回調(diào)函數(shù)作為參數(shù)
    const y2 = g.next(url); // 傳入url作為參數(shù),最終會(huì)賦值給上面代碼中的res1。 y2 = { value: f, done: false }
    y2.value(data => {
        g.next(data); // 傳入data作為參數(shù),會(huì)賦值給上面代碼中的res2。至此,迭代也完成了。
    });
});

// 最終的輸出為:
// 1s后輸出:res1 ajax返回了
// 1s后輸出:res2 ajax返回了

在上面的代碼中,我們使用generator實(shí)現(xiàn)了依次執(zhí)行兩個(gè)異步操作。上面的代碼看起來是比較復(fù)雜的。整個(gè)的邏輯在gen這個(gè)generator function里,然后我們手動(dòng)執(zhí)行完了g這個(gè)generator。按照上面的代碼,如果我們想再加入一個(gè)ajax請(qǐng)求,需要先修改generator function,然后修改generator的執(zhí)行邏輯。我們來實(shí)現(xiàn)一個(gè)自動(dòng)的流程,只需要定義好generator,讓它自動(dòng)執(zhí)行。

function autoRun(generatorFun) {
    const generator = generatorFun();
    const run = function(data){
        const res = generator.next(data);
        if(res.done) {
            return;
        }
        return res.value(run);
    }
    run();
}

這下,我們就可以專注于generator function的邏輯了。

function* gen() {
    const res1 = yield thunkAjax("http://url1.xxxx");
    console.log("res1", res1);
    const res2 = yield thunkAjax(res1);
    console.log("res2", res2);
    const res3 = yield thunkAjax(res2);
    console.log("res3", res3);
    ...
}
// 自動(dòng)執(zhí)行
autoRun(gen);
著名的co就是一個(gè)自動(dòng)執(zhí)行g(shù)enerator的庫。

上面的代碼中,gen函數(shù)體內(nèi),我們用同步代碼的寫法,實(shí)現(xiàn)了異步操作。可以看到,用gererator來執(zhí)行異步操作,在代碼可讀性、可擴(kuò)展性上面,是很有優(yōu)勢(shì)的。如今,我們或許會(huì)像下面這樣來寫上面的邏輯:

const fn = async function(){
    const res1 = await func1;
    console.log(res1);
    const res2 = await func2;
    console.log(res2);
    ...
}
fn();
寫在后面

本文從for..of入手,梳理了javascript中的兩個(gè)重要概念:iterator和generator。并且介紹了兩者在異步操作中的應(yīng)用。符合預(yù)期。下一篇文章中,將介紹async、await,任務(wù)隊(duì)列的相關(guān)內(nèi)容,希望能對(duì)js中的異步代碼及其寫法有一個(gè)更深入,全面的認(rèn)識(shí)。

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

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

相關(guān)文章

  • JS基礎(chǔ)JavaScript中的for...of說起(下) - asyncawait

    摘要:基礎(chǔ)從中的說起上和在異步操作中使用和是一件比較費(fèi)勁的事情,而給我們提供了更為簡(jiǎn)便的和。表達(dá)式會(huì)暫停當(dāng)前的執(zhí)行,等待處理完成。若正常處理,其回調(diào)的函數(shù)參數(shù)作為表達(dá)式的值,繼續(xù)執(zhí)行。若處理異常,表達(dá)式會(huì)把的異常原因拋出。 寫在前面 本文首發(fā)于公眾號(hào):【符合預(yù)期的CoyPan】 在上一篇文章中,梳理了javascript中的兩個(gè)重要概念:iterator和generator,并且介紹了兩者在...

    hufeng 評(píng)論0 收藏0
  • ES6 的 for..of Generator,偽數(shù)組 jQuery 對(duì)象說起

    摘要:引用自可迭代對(duì)象和迭代器不以規(guī)矩,不成方圓為了使某個(gè)對(duì)象成為可迭代對(duì)象象,它必須實(shí)現(xiàn)方法,也就是說,它得有一個(gè)是的屬性。的遍歷,絕對(duì)應(yīng)該用。 pseudo 英 [sju:d??] 美 [su:do?]adj.假的,虛偽的n.[口]假冒的人,偽君子 pseudo-array 英 [sju:d???re?] 美 [sju:d???re?][計(jì)] 偽數(shù)組 jQuery 對(duì)象是偽數(shù)組 兩個(gè)...

    Harriet666 評(píng)論0 收藏0
  • ES2018 新特征之:異步迭代器 for-await-of

    摘要:不幸的是,迭代器不能用來表示這樣的數(shù)據(jù)源。即使是的迭代器也是不夠的,因?yàn)樗氖钱惒降模堑餍枰酱_定狀態(tài)。異步迭代器一個(gè)異步迭代器就像一個(gè)迭代器,除了它的方法返回一個(gè)的。 ES2018 新特性 異步迭代器(本文) 正則表達(dá)式反向(lookbehind)斷言 正則表達(dá)式 Unicode 轉(zhuǎn)義 非轉(zhuǎn)義序列的模板字符串 正則表達(dá)式 s/dotAll 模式 正則表達(dá)式命名捕獲組 對(duì)...

    klivitamJ 評(píng)論0 收藏0
  • 賀老微博引出的“遍歷器(Iterators)加速那些奧秘”

    摘要:我關(guān)注的賀老賀師俊前輩最近發(fā)表個(gè)這樣一條微博雖然這條微博沒有引起大范圍的關(guān)注和討論,但是作為新人,我陷入了思考。通過賀老的微博,對(duì)一個(gè)問題進(jìn)行探究,最終找到核心成員的一文,進(jìn)行參考并翻譯。 我關(guān)注的賀老—賀師俊前輩@johnhax 最近發(fā)表個(gè)這樣一條微博: showImg(https://segmentfault.com/img/remote/1460000010452807); 雖然...

    XUI 評(píng)論0 收藏0
  • JavaScript ES6相關(guān)的一些知識(shí)(/let、const/箭頭函數(shù)/Promise/gene

    摘要:的精髓在于,用維護(hù)狀態(tài)傳遞狀態(tài)的方式使得回調(diào)函數(shù)能夠及時(shí)調(diào)用,比傳遞要簡(jiǎn)單靈活的其他方法用于指定發(fā)生錯(cuò)誤時(shí)的回調(diào)函數(shù),等同于部分和的區(qū)別在發(fā)生異常,在中捕獲不到能夠捕獲異常。 ES6是個(gè)啥 ECMAScript是國(guó)際通過的標(biāo)準(zhǔn)化腳本語言JavaScript由ES,BOM,DOM組成ES是JavaScript的語言規(guī)范,同時(shí)JavaScript是ES的實(shí)現(xiàn)和擴(kuò)展6就是JavaScript...

    opengps 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<