<kbd id="5sdj3"></kbd>
<th id="5sdj3"></th>

  • <dd id="5sdj3"><form id="5sdj3"></form></dd>
    <td id="5sdj3"><form id="5sdj3"><big id="5sdj3"></big></form></td><del id="5sdj3"></del>

  • <dd id="5sdj3"></dd>
    <dfn id="5sdj3"></dfn>
  • <th id="5sdj3"></th>
    <tfoot id="5sdj3"><menuitem id="5sdj3"></menuitem></tfoot>

  • <td id="5sdj3"><form id="5sdj3"><menu id="5sdj3"></menu></form></td>
  • <kbd id="5sdj3"><form id="5sdj3"></form></kbd>

    徹底理解 for of 和 Iterator

    共 9835字,需瀏覽 20分鐘

     ·

    2021-02-02 23:40

    本文主要來(lái)說(shuō)下ES6Iterator,目的在于理解它的概念、作用、以及現(xiàn)有的應(yīng)用,最后學(xué)以致用。

    Iterator可以說(shuō)是ES6內(nèi)相當(dāng)重大的一個(gè)特性,也是很多其他特性運(yùn)行的基石。

    為什么Iterator地位如此之高呢?

    從一個(gè)變量說(shuō)起

    var?arr?=?['紅','綠','藍(lán)'];

    上面是一個(gè)普通的數(shù)組,如果我要獲取他的每一項(xiàng)數(shù)據(jù),應(yīng)該怎么做?

    這個(gè)還不簡(jiǎn)單,直接來(lái)個(gè) for循環(huán),如果你覺(jué)得循環(huán) low,那就來(lái)個(gè) forEach 唄。

    ok,立刻擼串代碼

    //for?循環(huán)
    for(var?i=0;i????console.log(arr[i]);
    }

    //forEacth
    arr.forEach(item=>{
    ????console.log(item);
    });

    //?結(jié)果?略

    ok,沒(méi)毛病。

    那咱們繼續(xù),請(qǐng)看下面代碼。給定一個(gè)字符串,如果我想輸出每一個(gè)字符怎么做?

    var?str='1234567890';

    有么有搞錯(cuò),這簡(jiǎn)單的讓人發(fā)笑。

    可以用 for in,也可以用 for 循環(huán),按照類(lèi)數(shù)組方式來(lái)處理。

    立刻擼串代碼

    //for?in
    for(var?s?in?str){
    ????console.log(str[s]);//s?是?屬性名稱(chēng)【key】
    }

    //轉(zhuǎn)為數(shù)組
    for(var?i?=0;iconsole.log(str[i]);
    }

    //或者轉(zhuǎn)換為數(shù)組
    Array.prototype.slice.call(str);

    不過(guò) for in 不是用來(lái)獲取數(shù)據(jù)的,他會(huì)遍歷對(duì)象上所有可枚舉的屬性,包括自身的和原型鏈上的,所以這個(gè)不保險(xiǎn)。

    emmm....沒(méi)啥問(wèn)題,那咱們繼續(xù)。

    請(qǐng)看下面代碼,給定一個(gè)map對(duì)象,然后輸出它每一項(xiàng)數(shù)據(jù)。

    var?map?=?new?Map();
    map.set('zhang','1000w');
    map.set('liu','200w');
    map.set('sun','100w');

    forEach 就妥妥的了。

    map.forEach((val,key)=>{
    ????console.log(val,key);
    })

    到這里看了這么多如此簡(jiǎn)單到令人發(fā)指的提問(wèn),估計(jì)都有些坐不住了,要掀桌子走人了。請(qǐng)稍后,慢慢往下看。

    發(fā)現(xiàn)問(wèn)題

    好了,在上一步幾個(gè)簡(jiǎn)單的問(wèn)題中,我們的操作都是獲得他們的每一項(xiàng)數(shù)據(jù)。

    當(dāng)然方法有很多種,實(shí)現(xiàn)方式也有很多,for 循環(huán),forEach,for in 啦。

    但是有沒(méi)有發(fā)現(xiàn)一個(gè)問(wèn)題,或者我們站在一個(gè)更高的維度去看待,其實(shí)這些方法都不能通用,也就是說(shuō)上面的這幾種集合數(shù)據(jù)不能使用統(tǒng)一的遍歷方法來(lái)進(jìn)行數(shù)據(jù)獲取。

    誰(shuí)說(shuō)的,能統(tǒng)一呀,都可以用 forEach來(lái)遍歷,數(shù)組和map 本身就支持,字符串我直接轉(zhuǎn)為數(shù)組后可以了。

    ok,這沒(méi)什么毛病。

    但是每次都要轉(zhuǎn)換,還要封裝,還有可能要侵入原型。

    那有沒(méi)有一種更好的,通用方法,讓開(kāi)發(fā)者用的更舒服,更爽呢?

    答案是肯定的,es5的時(shí)候還沒(méi)出現(xiàn),升級(jí)到 es6就有了。

    NB的 for of,扒一扒

    這個(gè)可以對(duì)不同數(shù)據(jù)結(jié)構(gòu)進(jìn)行統(tǒng)一遍歷的方式就是 es6for of 循環(huán)。

    for of 循環(huán) 和 古老的for 循環(huán)很像呀。不就是個(gè)新增語(yǔ)法么。

    引用阮大佬書(shū)中一句話(huà),相信一看便知。

    ES6 借鑒 C++、Java、C# 和 Python 語(yǔ)言,引入了for...of循環(huán)。作為遍歷所有數(shù)據(jù)結(jié)構(gòu)的統(tǒng)一的方法。

    關(guān)鍵在于統(tǒng)一,另一個(gè)就是直接取值,簡(jiǎn)化操作,不需要在聲明和維護(hù)什么變量、對(duì)數(shù)據(jù)做轉(zhuǎn)換。

    原來(lái)for of 這么牛,for 循環(huán)搞不定的你可以搞定。

    為什么 for of 能具備這個(gè)能力,可以為不同的數(shù)據(jù)結(jié)構(gòu)提供一種統(tǒng)一的數(shù)據(jù)獲取方式。

    for of 真的這么強(qiáng)大嗎,他背后的機(jī)制是什么?

    其實(shí)for of 并不是真的強(qiáng)大,他只是一種ES6新的語(yǔ)法而已。

    并不是所有的對(duì)象都能使用 for of,只有實(shí)現(xiàn)了Iterator接口的對(duì)象才能夠使用 for of 來(lái)進(jìn)行遍歷取值。

    所以說(shuō) for of 只是語(yǔ)法糖,真正的主角是Iterator。

    What ? Iterator.....

    主角登場(chǎng)- Iterator 迭代器

    Iterator 是一種接口,目的是為不同的數(shù)據(jù)結(jié)構(gòu)提供統(tǒng)一的數(shù)據(jù)訪問(wèn)機(jī)制。也可以理解為 Iterator 接口主要為 for of 服務(wù)的,供for...of進(jìn)行消費(fèi)。

    其實(shí)在很多后端語(yǔ)言多年前早已存在 Iterator 這個(gè)特性,如 java、C++、C#等。

    既然他是一種接口,那我們應(yīng)該怎樣實(shí)現(xiàn)這個(gè)接口呢?實(shí)現(xiàn)規(guī)則是什么樣的呢?

    因?yàn)?javascript 語(yǔ)言里沒(méi)有接口的概念,這里我們可以理解成它是一種特殊的對(duì)象 - 迭代器對(duì)象,返回此對(duì)象的方法叫做迭代器方法。

    首先他作為一個(gè)對(duì)象,此對(duì)象具有一個(gè)next方法,每次調(diào)用 next 方法都會(huì)返回一個(gè)結(jié)果值。

    這個(gè)結(jié)果值是一個(gè) object,包含兩個(gè)屬性,valuedone。

    value表示具體的返回值,done 是布爾類(lèi)型的,表示集合是否遍歷完成或者是否后續(xù)還有可用數(shù)據(jù),沒(méi)有可用數(shù)據(jù)則返回 true,否則返回 false

    另外內(nèi)部會(huì)維護(hù)一個(gè)指針,用來(lái)指向當(dāng)前集合的位置,每調(diào)用一次 next 方法,指針都會(huì)向后移動(dòng)一個(gè)位置(可以想象成數(shù)組的索引)。

    看下代碼實(shí)現(xiàn)

    function?getIterator(list)?{
    ????var?i?=?0;
    ????return?{
    ????????next:?function()?{
    ????????????var?done?=?(i?>=?list.length);
    ????????????var?value?=?!done???list[i++]?:?undefined;
    ????????????return?{
    ????????????????done:?done,
    ????????????????value:?value
    ????????????};
    ????????}
    ????};
    }
    var?it?=?getIterator(['a',?'b',?'c']);
    console.log(it.next());?//?{value:?"a",?done:?false}
    console.log(it.next());?//?{value:?"b",?done:?false}
    console.log(it.next());?//?{value:?"c",?done:?false}
    console.log(it.next());?//?"{?value:?undefined,?done:?true?}"
    console.log(it.next());?//?"{?value:?undefined,?done:?true?}"
    console.log(it.next());?//?"{?value:?undefined,?done:?true?}"

    上面代碼便是根據(jù)迭代器的基本概念衍生出來(lái)的一個(gè)模擬實(shí)現(xiàn)。

    • getIterator方法返回一個(gè)對(duì)象 - 可迭代對(duì)象
    • 對(duì)象具有一個(gè)next 方法,next 方法內(nèi)部通過(guò)閉包來(lái)保存指針 i 的值,每次調(diào)用 next 方法 i 的值都會(huì)+1.
    • 然后根據(jù) i 的值從數(shù)組內(nèi)取出數(shù)據(jù)作為 value,然后通過(guò)索引判斷得到 done的值。
    • 當(dāng) i=3的時(shí)候,超過(guò)數(shù)組的最大索引,無(wú)可用數(shù)據(jù)返回,此時(shí)done 為true,遍歷完成。

    可迭代對(duì)象

    到這里我們已經(jīng)大概了解了 Iterator, 以及如何創(chuàng)建一個(gè)迭代器對(duì)象。但是他和 for of 有什么關(guān)系呢?

    for of 運(yùn)行機(jī)制

    當(dāng) for of執(zhí)行的時(shí)候,循環(huán)過(guò)程中引擎就會(huì)自動(dòng)調(diào)用這個(gè)對(duì)象上的迭代器方法, 依次執(zhí)行迭代器對(duì)象的 next 方法,將 next 返回值賦值給 for of 內(nèi)的變量,從而得到具體的值。

    我覺(jué)得上面一句話(huà)包含了一個(gè)重要的信息- “對(duì)象上的迭代器方法”。

    實(shí)現(xiàn)可迭代對(duì)象

    對(duì)象上怎么會(huì)有迭代器方法呢?

    ES6里規(guī)定,只要在對(duì)象的屬性上部署了Iterator接口,具體形式為給對(duì)象添加Symbol.iterator屬性,此屬性指向一個(gè)迭代器方法,這個(gè)迭代器會(huì)返回一個(gè)特殊的對(duì)象 - 迭代器對(duì)象。

    而部署這個(gè)屬性并且實(shí)現(xiàn)了迭代器方法后的對(duì)象叫做可迭代對(duì)象。

    此時(shí),這個(gè)對(duì)象就是可迭代的,也就是可以被 for of 遍歷。

    Symbol.iterator,它是一個(gè)表達(dá)式,返回Symbol對(duì)象的iterator屬性,這是一個(gè)預(yù)定義好的、類(lèi)型為 Symbol 的特殊值。

    舉個(gè)例子

    普通的對(duì)象是不能被 for of 遍歷的,直接食用會(huì)報(bào)錯(cuò)。

    var?obj?=?{};

    for(var?k?of?obj){
    ????
    }

    obj 不是可迭代的對(duì)象。

    那么我們來(lái),讓一個(gè)對(duì)象變成可迭代對(duì)象,按照協(xié)議也就是規(guī)定來(lái)實(shí)現(xiàn)即可。

    iterableObj 對(duì)象上部署 Symbol.iterator屬性,然后為其創(chuàng)建一個(gè)迭代器方法,迭代器的規(guī)則上面我們已經(jīng)說(shuō)過(guò)啦。

    var?iterableObj?=?{
    ????items:[100,200,300],
    ????[Symbol.iterator]:function(){
    ????var?self=this;
    ????var?i?=?0;
    ????return?{
    ????????next:?function()?{
    ????????????var?done?=?(i?>=?self.items.length);
    ????????????var?value?=?!done???self.items[i++]?:?undefined;
    ????????????return?{
    ????????????????done:?done,
    ????????????????value:?value
    ????????????};
    ????????}
    ????};
    ????}
    }

    //遍歷它
    for(var?item?of?iterableObj){
    ????console.log(item);?//100,200,300
    }

    就這么簡(jiǎn)單,上面這個(gè)對(duì)象就是可迭代對(duì)象了,可以被 for of 消費(fèi)了。

    Iterator 原生應(yīng)用場(chǎng)景

    我們?cè)倩氐阶铋_(kāi)始使用 for of 來(lái)進(jìn)行遍歷字符串、數(shù)組、map,我們并沒(méi)有為他們部署Iterator接口,仍然可以使用 for of 遍歷。

    這是因?yàn)樵?ES6中有些對(duì)象已經(jīng)默認(rèn)部署了此接口,不需要做任何處理,就可以使用 for of 來(lái)進(jìn)行遍歷取值。

    不信?咿,你好難搞,我不要你說(shuō) - 信,我要我說(shuō) - 信。

    看看能不能拿到它們的迭代器。

    數(shù)組

    //數(shù)組
    var?arr=[100,200,300];

    var?iteratorObj=??arr[Symbol.iterator]();//得到迭代器方法,返回迭代器對(duì)象

    console.log(iteratorObj.next());
    console.log(iteratorObj.next());
    console.log(iteratorObj.next());
    console.log(iteratorObj.next());


    字符串

    因?yàn)樽址旧淼闹凳怯行虻?,并且具有?lèi)數(shù)組的特性,支持通過(guò)索引訪問(wèn),所以也默認(rèn)部署了iterator接口。

    var?str='abc';

    var?strIteratorObj?=?str[Symbol.iterator]();//得到迭代器

    console.log(strIteratorObj.next());
    console.log(strIteratorObj.next());
    console.log(strIteratorObj.next());
    console.log(strIteratorObj.next());

    或者直接看原型上是否部署了這個(gè)屬性即可。

    arguments 類(lèi)數(shù)組

    函數(shù)內(nèi)的arguments 是一個(gè)類(lèi)數(shù)組,他也支持 for of,因?yàn)樗麅?nèi)部也部署了Iterator 接口。

    我們都知道對(duì)象是默認(rèn)沒(méi)有部署這個(gè)接口的,所以arguments這個(gè)屬性沒(méi)有在原型上,而在在對(duì)象自身的屬性上。

    function?test(){
    ????var?obj?=?arguments[Symbol.iterator]();
    ???console.log(?arguments.hasOwnProperty(Symbol.iterator));
    ???console.log(?arguments);
    ???console.log(obj.next());
    }

    test(1,2,3);

    總結(jié)來(lái)說(shuō),已默認(rèn)部署 Iterator 接口的對(duì)象主要包括數(shù)組、字符串、Set、Map 、類(lèi)似數(shù)組的對(duì)象(比如arguments對(duì)象、DOM NodeList 對(duì)象)。

    代碼驗(yàn)證略,都是一個(gè)套路,不多說(shuō)。

    Iterator 另外一個(gè)作用

    Iterator除了可以為不同的數(shù)據(jù)結(jié)構(gòu)提供一種統(tǒng)一的數(shù)據(jù)訪問(wèn)方式,還有沒(méi)有發(fā)現(xiàn)其他的作用?

    那就是數(shù)據(jù)可定制性,因?yàn)槲覀兛梢噪S意的控制迭代器的 value 值。

    比如:數(shù)組本身就是一個(gè)可迭代的,我們可以覆蓋他的默認(rèn)迭代器。

    var?arr=[100,200,300];

    for(var?o?of?arr){
    ????console.log(o);
    }

    for of 數(shù)組默認(rèn)輸出如下

    經(jīng)過(guò)我們的改造

    var?arr=[100,200,300];
    arr[Symbol.iterator]=function(){

    ????var?self=this;
    ????var?i?=?0;
    ????return?{
    ????????next:?function()?{
    ????????????var?done?=?(i?>=?self.length);
    ????????????var?value?=?!done???self[i++]?:?undefined;
    ????????????return?{
    ????????????????done:?done,
    ????????????????value:?value
    ????????????};
    ????????}
    ????};
    }

    for(var?o?of?arr){
    ????console.log(o);
    }

    對(duì)象為什么沒(méi)有默認(rèn)部署

    對(duì)象可能有各種屬性,不像數(shù)組的值是有序的。

    所以遍歷的時(shí)候根本不知道如何確定他們的先后順序,所以需要我們根據(jù)情況手動(dòng)實(shí)現(xiàn)。

    擴(kuò)展

    for of 中斷

    我們都知道普通的 for 循環(huán)是可以隨時(shí)中斷的,那 for of 是否可以呢?

    答案是肯定的,for of機(jī)制兼顧了forforEach

    迭代器除了必須next 方法外,還有兩個(gè)可選的方法 returnthrow方法。

    如果 for of 循環(huán)提前退出,則會(huì)自動(dòng)調(diào)用 return 方法,需要注意的是 return 方法必須有返回值,且返回值必須是 一個(gè)object。

    ps:以?huà)伋霎惓5姆绞酵顺?,?huì)先執(zhí)行 return 方法再拋出異常。

    var?iterableObj?=?{
    ????items:[100,200,300],
    ????[Symbol.iterator]:function(){
    ????var?self=this;
    ????var?i?=?0;
    ????return?{
    ????????next:?function()?{
    ????????????var?done?=?(i?>=?self.items.length);
    ????????????var?value?=?!done???self.items[i++]?:?undefined;
    ????????????return?{
    ????????????????done:?done,
    ????????????????value:?value
    ????????????};
    ????????},
    ????????return(){
    ????????????console.log('提前退出');
    ????????????return?{//必須返回一個(gè)對(duì)象
    ????????????????done:true
    ????????????}
    ????????}
    ????};
    ????}

    }

    for(var?item?of?iterableObj){
    ????console.log(item);
    ????if(item===200){
    ????????break;
    ????}
    }

    for(var?item?of?iterableObj){
    ????console.log(item);
    ????throw?new?Error();
    }

    ps:throw 方法這里先不說(shuō),這里不是他的用武之地,后續(xù)文章見(jiàn)。

    不止 for of

    除了 for of 執(zhí)行的時(shí)候會(huì)自動(dòng)調(diào)用對(duì)象的Iterator方法,那么ES6里還有沒(méi)有其他的語(yǔ)法形式?

    解構(gòu)賦值

    對(duì)可迭代對(duì)象進(jìn)行解構(gòu)賦值的時(shí)候,會(huì)默認(rèn)調(diào)用Symbol.iterator方法。

    //字符串
    var?str='12345';
    var?[a,b]=str;
    console.log(a,b);?//?1?2

    //map
    var?map?=?new?Map();
    map.set('我','前端');
    map.set('是','技術(shù)');
    map.set('誰(shuí)','江湖');
    map.set('作者','zz_jesse');

    var?[d,e]=map;
    console.log(d,e);
    //["我",?"前端"]?["是",?"技術(shù)"]
    ....

    同樣如果對(duì)一個(gè)普通對(duì)象進(jìn)行解構(gòu),則會(huì)報(bào)錯(cuò)。

    因?yàn)槠胀▽?duì)象不是可迭代對(duì)象。

    var?[d,e]={name:'zhang'};

    從一個(gè)自定義的可迭代對(duì)象進(jìn)行解構(gòu)賦值。

    var?iterableObj?=?{
    ????items:['紅','綠','藍(lán)'],
    ????[Symbol.iterator]:function(){
    ????var?self=this;
    ????var?i?=?0;
    ????return?{
    ????????next:?function()?{
    ????????????var?done?=?(i?>=?self.items.length);
    ????????????var?value?=?!done???self.items[i++]?:?undefined;
    ????????????return?{
    ????????????????done:?done,
    ????????????????value:?value
    ????????????};
    ????????}
    ?????};
    ???}
    }

    var?[d,e]=iterableObj;
    console.log(d,e);//紅?綠?

    解構(gòu)賦值的變量的值就是迭代器對(duì)象的 next 方法的返回值,且是按順序返回。

    擴(kuò)展運(yùn)算符

    擴(kuò)展運(yùn)算符的執(zhí)行(...)也會(huì)默認(rèn)調(diào)用它的Symbol.iterator方法,可以將當(dāng)前迭代對(duì)象轉(zhuǎn)換為數(shù)組。

    //字符串
    var?str='1234';
    console.log([...str]);//[1,2,3,4]??轉(zhuǎn)換為數(shù)組


    //map?對(duì)象
    var?map=new?Map([[1,2],[3,4]]);
    [...map]?//[[1,2],[3,4]

    //set?對(duì)象
    var?set=new?Set([1,2,3]);
    [...set]?//[1,2,3]

    通用普通對(duì)象是不可以轉(zhuǎn)為數(shù)組的。

    var?obj={name:'zhang'};
    [..obj]//報(bào)錯(cuò)

    作為數(shù)據(jù)源

    作為一些數(shù)據(jù)的數(shù)據(jù)源,比如某些api 方法的參數(shù)是接收一個(gè)數(shù)組,都會(huì)默認(rèn)的調(diào)用自身迭代器。

    例如:Set、Map、Array.from 等

    //為了證明,先把一個(gè)數(shù)組的默認(rèn)迭代器給覆蓋掉

    var?arr=[100,200,300];

    arr[Symbol.iterator]=function(){

    ????var?self=this;
    ????var?i?=?0;
    ????return?{
    ????????next:?function()?{
    ????????????var?done?=?(i?>=?self.length);
    ????????????var?value?=?!done???self[i++]?:?undefined;
    ????????????return?{
    ????????????????done:?done,
    ????????????????value:?value+'前端技術(shù)江湖'?//注意這里
    ????????????};
    ????????}
    ????};

    }

    for(var?o?of?arr){
    ????console.log(o);
    }

    //?100前端技術(shù)江湖
    //?200前端技術(shù)江湖
    //?300前端技術(shù)江湖

    已覆蓋完成

    //生成?set??對(duì)象
    var?set??=?new?Set(arr);
    //調(diào)用?Array.from方法
    Array.from(arr);

    yield* ?關(guān)鍵字

    yield*后面跟的是一個(gè)可遍歷的結(jié)構(gòu),執(zhí)行時(shí)也會(huì)調(diào)用迭代器函數(shù)。

    let?foo?=?function*?()?{
    ??yield?1;
    ??yield*?[2,3,4];
    ??yield?5;
    };

    yield 需要著重說(shuō)明, 下一節(jié)再詳細(xì)介紹。

    判斷對(duì)象是否可迭代

    既然可迭代對(duì)象的規(guī)則必須在對(duì)象上部署Symbol.iterator屬性,那么我們基本上就可以通過(guò)此屬來(lái)判斷對(duì)象是否為可迭代對(duì)象,然后就可以知道是否能使用 for of 取值了。

    function?isIterable(object)?{
    ????return?typeof?object[Symbol.iterator]?===?"function";
    }
    console.log(isIterable('abcdefg'));?//?true
    console.log(isIterable([1,?2,?3]));?//?true
    console.log(isIterable("Hello"));?//?true
    console.log(isIterable(new?Map()));?//?true
    console.log(isIterable(new?Set()));?//?true
    console.log(isIterable(new?WeakMap()));?//?false
    console.log(isIterable(new?WeakSet()));?//?false

    總結(jié)

    ES6的出現(xiàn)帶來(lái)了很多新的數(shù)據(jù)結(jié)構(gòu),比如 Map ,Set ,所以為了數(shù)據(jù)獲取的方便,增加了一種統(tǒng)一獲取數(shù)據(jù)的方式 for of 。而 for of 執(zhí)行的時(shí)候引擎會(huì)自動(dòng)調(diào)用對(duì)象的迭代器來(lái)取值。

    不是所有的對(duì)象都支持這種方式,必須是實(shí)現(xiàn)了Iterator接口的才可以,這樣的對(duì)象我們稱(chēng)他們?yōu)榭傻鷮?duì)象。

    迭代器實(shí)現(xiàn)方式根據(jù)可迭代協(xié)議,迭代器協(xié)議實(shí)現(xiàn)即可。

    除了統(tǒng)一數(shù)據(jù)訪問(wèn)方式,還可以自定義得到的數(shù)據(jù)內(nèi)容,隨便怎樣,只要是你需要的。

    迭代器是一個(gè)方法, 用來(lái)返回迭代器對(duì)象。

    可迭代對(duì)象是部署了 Iterator 接口的對(duì)象,同時(shí)擁有正確的迭代器方法。

    ES6內(nèi)很多地方都應(yīng)用了Iterator,平時(shí)可以多留意觀察,多想一步。

    是結(jié)束也是開(kāi)始

    到這里我們已經(jīng)可以根據(jù)迭代器的規(guī)則自定義迭代器了,但實(shí)現(xiàn)的過(guò)程有些復(fù)雜,畢竟需要自己來(lái)維護(hù)內(nèi)部指針,有不少的邏輯處理,難免會(huì)出錯(cuò)。

    那有沒(méi)有更優(yōu)雅的實(shí)現(xiàn)方式呢?

    有,那就是-Generator -生成器 。

    let?obj?=?{
    ??*?[Symbol.iterator]()?{
    ????yield?'hello';
    ????yield?'world';
    ??}
    };

    for?(let?x?of?obj)?{
    ??console.log(x);
    }
    //?"hello"
    //?"world"

    可以看出它非常簡(jiǎn)潔,無(wú)需過(guò)多代碼就可以生成一個(gè)迭代器。

    它除了可以作為生成迭代器的語(yǔ)法糖,他還有更多神奇的能力。

    這次就先搞定Iterator,下次搞 Generator

    練習(xí)

    如果覺(jué)得本文有收獲的話(huà),可以試著做做下面的練習(xí)題,加深下理解,然后在評(píng)論內(nèi)寫(xiě)上你的答案。

    1. 寫(xiě)一個(gè)迭代器(Iterator)對(duì)象 。
    2. 自定義一個(gè)可迭代對(duì)象。
    3. 說(shuō)說(shuō)你對(duì)Iterator的理解,總結(jié)性輸出下。

    參考

    https://es6.ruanyifeng.com/#docs/iterator

    https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Iteration_protocols

    https://www.cnblogs.com/xiaohuochai/p/7253466.html

    月初福利

    每月1號(hào)組織小伙伴們來(lái)抽獎(jiǎng)。

    給本文發(fā)評(píng)論或者點(diǎn)贊就可以參與抽獎(jiǎng)啦




    僅限于關(guān)注本號(hào)小伙伴參與哦


    點(diǎn)個(gè)『在看』支持下?


    瀏覽 99
    點(diǎn)贊
    評(píng)論
    收藏
    分享

    手機(jī)掃一掃分享

    分享
    舉報(bào)
    評(píng)論
    圖片
    表情
    推薦
    點(diǎn)贊
    評(píng)論
    收藏
    分享

    手機(jī)掃一掃分享

    分享
    舉報(bào)

    <kbd id="5sdj3"></kbd>
    <th id="5sdj3"></th>

  • <dd id="5sdj3"><form id="5sdj3"></form></dd>
    <td id="5sdj3"><form id="5sdj3"><big id="5sdj3"></big></form></td><del id="5sdj3"></del>

  • <dd id="5sdj3"></dd>
    <dfn id="5sdj3"></dfn>
  • <th id="5sdj3"></th>
    <tfoot id="5sdj3"><menuitem id="5sdj3"></menuitem></tfoot>

  • <td id="5sdj3"><form id="5sdj3"><menu id="5sdj3"></menu></form></td>
  • <kbd id="5sdj3"><form id="5sdj3"></form></kbd>
    高清人妻无码 | 【乱子伦】国产精品 | 自拍偷拍网站 | 色综合天天综合网天天狠天天 | 欧美另类爱爱小视频 |