欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JavaScript可迭代對(duì)象詳細(xì)介紹

 更新時(shí)間:2022年06月10日 08:33:17   作者:czpcalm  
ES6中引入了迭代器與可迭代對(duì)象的概念,并且提供了對(duì)可迭代對(duì)象的相關(guān)支持,如for...of循環(huán),Map(iterable)構(gòu)造器,展開(kāi)語(yǔ)法...等。讓我們對(duì)數(shù)組外的數(shù)據(jù)集合的遍歷操作也得到極大簡(jiǎn)化

1、迭代器

迭代器是借鑒C++等語(yǔ)言的概念,迭代器的原理就像指針一樣,它指向數(shù)據(jù)集合中的某個(gè)元素,你可以獲取它指向的元素,也可以移動(dòng)它以獲取其它元素。迭代器類(lèi)似于數(shù)組中下標(biāo)的拓展,各種數(shù)據(jù)結(jié)構(gòu),如鏈表(List)、集合(Set)、映射(Map)都有與之對(duì)應(yīng)的迭代器。

JS中的迭代器是專(zhuān)門(mén)為了遍歷這一操作設(shè)計(jì)的。每次獲取到的迭代器總是初始指向第一個(gè)元素,并且迭代器只有next()一種行為,直到獲取到數(shù)據(jù)集的最后一個(gè)元素。我們無(wú)法靈活移動(dòng)迭代器的位置,所以,迭代器的任務(wù),是按某種次序遍歷數(shù)據(jù)集中的元素。

JS規(guī)定,迭代器必須實(shí)現(xiàn)next()接口,它應(yīng)該返回當(dāng)前元素并將迭代器指向下一個(gè)元素,返回的對(duì)象格式為{value:元素值, done:是否遍歷結(jié)束},其中,done是一個(gè)布爾值。done屬性為true的時(shí)候,我們默認(rèn)不會(huì)去讀取value, 所以最后返回的經(jīng)常是{value: undifined, done: true},注意,返回類(lèi)似{value: 2, done: true} 不會(huì)導(dǎo)致錯(cuò)誤,但是因?yàn)?code>done設(shè)置為true,在for...of等操作中都會(huì)忽略value的值。因此,done:falsevalue:undifined可以省略。一個(gè)簡(jiǎn)單的JS迭代器像這樣:

let iter = {
    i: 0,
    next() {
        if (this.i > 10) return { done: true };
        return { value: this.i++ };
    }
}
//手動(dòng)使用迭代器
console.log(iter.next());  //{ value: 0 }
console.log(iter.next());   //{ value: 1 }
while (true) {     
    let item = iter.next();
    if (!item.done) {
        console.log(item.value);     //打印從2到10
    } else {
        break;
    }
}

可以看到,迭代器與普通的JS對(duì)象沒(méi)有區(qū)別,它就是一個(gè)用于實(shí)現(xiàn)迭代的對(duì)象。手動(dòng)操作迭代器并沒(méi)有什么實(shí)用性,迭代器的作用是附著在對(duì)象上,讓一個(gè)對(duì)象,或者數(shù)據(jù)結(jié)構(gòu)成為可迭代對(duì)象。

2、迭代器接口與可迭代對(duì)象

迭代器接口是我們獲取對(duì)象迭代器時(shí)默認(rèn)調(diào)用的接口,一個(gè)實(shí)現(xiàn)了迭代接口的對(duì)象即是可迭代對(duì)象。JS的默認(rèn)迭代接口是[Symbol.iterator], 一個(gè)對(duì)象實(shí)現(xiàn)了[Symbol.iterator]接口就成為了可迭代對(duì)象。

[Symbol.iterator]是一個(gè)特殊的Symbol屬性,它用于JS內(nèi)部檢測(cè)一個(gè)對(duì)象是否為可迭代對(duì)象。接口一詞的含義代表它是一個(gè)函數(shù),其結(jié)果應(yīng)該放回一個(gè)迭代器。結(jié)合上面迭代器必須要有next()操作,所以,對(duì)可迭代對(duì)象,調(diào)用鏈iterableObj[Symbol.iterator]().next()應(yīng)該是可行的。數(shù)組是最具代表性的可迭代對(duì)象,讓我們拿數(shù)組測(cè)試一下:

arr = [1, '2', {a: 3}];
let arrIt = arr[Symbol.iterator]();    //獲取數(shù)組迭代器
console.log(arrIt.next());   //{ value: 1, done: false }
console.log(arrIt.next());  //{ value: '2', done: false }
console.log(arrIt.next());   //{ value: { a: 3 }, done: false }
console.log(arrIt.next());  //{ value: undefined, done: true }

可以看到,迭代器的next()接口確實(shí)如愿工作,并且返回上述的結(jié)構(gòu)。

3、自定義可迭代對(duì)象

現(xiàn)在,讓我們來(lái)實(shí)現(xiàn)幾個(gè)可迭代對(duì)象,這十分簡(jiǎn)單,只要:

  • 實(shí)現(xiàn)對(duì)象的迭代器接口[Symbol.iterator](),注意它是一個(gè)方法,
  • 在迭代器接口中返回一個(gè)迭代器對(duì)象,
  • 確保迭代器對(duì)象具有next()接口,并且返回{value: v, done: bool}的結(jié)構(gòu)。

3.1、可迭代的Range對(duì)象

作為第一個(gè)可迭代對(duì)象,我們來(lái)實(shí)現(xiàn)類(lèi)似python中的range(from, to),不過(guò)這里使用Range對(duì)象來(lái)封裝一個(gè)左閉右開(kāi)的范圍[from, to)。

function Range(from, to) {
    this.from = from;
    this.to = to;
}
Range.prototype[Symbol.iterator] = function () {
    //返回一個(gè)迭代器對(duì)象
    return {
        cur: this.from,
        to: this.to, //保證next()中可以獲取
        next() {
            return (this.cur < this.to) ? {
                value: this.cur++,
                done: false
            } : {
                value: undefined,
                done: true
            };
        }
    }
}
let range = new Range(5, 11);  //創(chuàng)建一個(gè)range對(duì)象
//使用for...of循環(huán)
for (const num of range) {
    console.log(num);    //依次打印5,6,7,8,9,10
}
//使用
let arrFromRange = Array.from(range);
console.log(arrFromRange);   //[5,6,7,8,9,10]

3.2、使用Generator函數(shù)作為迭代器接口

因?yàn)镚enerator函數(shù)產(chǎn)生的generator對(duì)象是一種特殊的迭代器,所以我們可以很方法地使用Generator函數(shù)作為對(duì)象的迭代器接口。使用Generator函數(shù)改寫(xiě)上面的迭代器接口:

Range.prototype[Symbol.iterator] = function* () {
    for (let i = this.from; i < this.to; i++) {
        yield i;
    }
}

這種寫(xiě)法更加簡(jiǎn)潔易懂,是最為推薦的寫(xiě)法,Generator函數(shù)中產(chǎn)生的值就是遍歷過(guò)程中得到的值。

3.3、可迭代的List

接下來(lái),我們自定義一個(gè)鏈表節(jié)點(diǎn)List,在此我們省去不必要的接口。

function ListNode(value) {
    this.value = value;
    this.nextNode = null;
}

function List(root) {
    this.cur = this.root = root;
}
//List的next接口
List.prototype.next = function () {
    if (this.cur) { //非尾哨兵節(jié)點(diǎn)
        let curNode = {
            value: this.cur.value
        };
        this.cur = this.cur.nextNode;
        return curNode;
    } else {
        return {
            done: true
        };
    }
}

List.next()實(shí)現(xiàn)了將鏈表指針后移的操縱,并且返回了移動(dòng)前節(jié)點(diǎn)的值,你可能注意到,我特意讓返回的對(duì)象格式與迭代器返回結(jié)果一致,下面你將看到這么做的原因?,F(xiàn)在我們讓List變成可迭代,按照之前的做法,使得List[Symbol.iterator]().next()能夠返回正確的{value: v, done: true}格式。是的,我們已經(jīng)畫(huà)好龍了,就差一個(gè)點(diǎn)睛之筆:

List.prototype[Symbol.iterator] = function () {
    return this;
}

隨手寫(xiě)一個(gè)測(cè)試:

let a = new ListNode('a'),
    b = new ListNode('b'),
    c = new ListNode('c');
a.nextNode = b, b.nextNode = c;
let list = new List(a);
for (let i of list) {
    console.log(i);  //a,b,c
}

Perfect! List的迭代器接口返回了它自己,利用了自身的next()接口完成迭代操作,也就是說(shuō)List的迭代器是List本身,我都為自己構(gòu)思的例子覺(jué)得巧妙。

3.3、可迭代的迭代器

上面的List例子會(huì)讓人覺(jué)得有點(diǎn)牽強(qiáng),list.next()的返回值為了迎合迭代器的要求,讓平時(shí)不得不使用let curValue = list.next().value來(lái)正確接收返回的節(jié)點(diǎn)值,確實(shí)。但是,這種做法在一種時(shí)候讓人覺(jué)得眼前一亮——讓迭代器稱(chēng)為可迭代對(duì)象,因?yàn)樽约壕褪强傻鳎屪约撼蔀樽约旱牡?,就?code>1=1一樣正確自然。

回到開(kāi)頭埋下的雷,我們只需要稍加改動(dòng)

let iter = {
    i: 0,
    next() {
        if (this.i > 10) return { done: true };
        return { value: this.i++ };
    },
    //讓迭代器的迭代器接口返回自身
     [Symbol.iterator]() {
        return this;
    }
}
//這樣,你就可以把迭代器用在任何可迭代對(duì)象的地方
for (let i of iter) {
    console.log(i);  
}

這樣,這個(gè)迭代器本身也是可迭代的。需要注意的是,內(nèi)置可迭代類(lèi)型的迭代器也都是可迭代的,類(lèi)似for(let i of arr[Symbol.iterator]())的操作是可行,其原理是讓Array的迭代器繼承Array.prototype。其它類(lèi)型也有類(lèi)似的繼承,如Generator與generator對(duì)象。

4、可迭代對(duì)象的意義

可迭代對(duì)象作為數(shù)組的擴(kuò)充,具有非凡的意義。在以前,對(duì)一個(gè)需要操作一組數(shù)據(jù)的接口,只有數(shù)組這種結(jié)構(gòu)能支持,非數(shù)組對(duì)象必須通過(guò)某種方式轉(zhuǎn)化為數(shù)組,完成之后,還可能需要還原成原來(lái)的結(jié)構(gòu),這種繁瑣的來(lái)回切換很不理想。有了可迭代對(duì)象的概念,這類(lèi)操作可以接受一個(gè)可迭代對(duì)象,數(shù)組是可迭代對(duì)象,所以之前的數(shù)組參數(shù)是仍然可行的,在此之上,任何實(shí)現(xiàn)了可迭代接口的對(duì)象,也能正常處理??紤]這個(gè)下面例子:

function sumInArray(arr){
    let sum=0;
    for(let i = 0;i<arr.length;i++){
        sum+=arr[i];
    }
    return sum;
}
function sumInIterable(iterable){
    let sum = 0;
    for(let num of iterable){
        sum+=num;
    }
    return sum;
}

sumInArray()只對(duì)數(shù)組友好,而sumInIterable()是所有可迭代對(duì)象通用的,例如我們前面的Range對(duì)象,iter對(duì)象。是的,數(shù)組到可迭代對(duì)象的提升,代表了接口的通用性的提升。這個(gè)道理太淺顯易懂,以至于你可能覺(jué)得我說(shuō)廢話,那么,請(qǐng)問(wèn)你在接口設(shè)計(jì)的時(shí)候,會(huì)考慮能否使用可迭代對(duì)象代替數(shù)組嗎?個(gè)人認(rèn)為這種提升很多時(shí)候是有益的,特別在一些應(yīng)用場(chǎng)景較多的接口,我發(fā)現(xiàn)很多ES6操作也是基于可迭代對(duì)象。如果有什么看法,也歡迎評(píng)論區(qū)探討。

5、使用可迭代對(duì)象

先認(rèn)識(shí)JS內(nèi)建的可迭代對(duì)象:

  • 非weak的數(shù)據(jù)結(jié)構(gòu),包括Array,Set, Map。
  • DOM中的NodeList對(duì)象。
  • String對(duì)象
  • 函數(shù)的arguments屬性。

再了解哪些操作是基于可迭代對(duì)象的:

  • for...of語(yǔ)法
  • ...iterable:展開(kāi)語(yǔ)法和解構(gòu)賦值
  • yield*語(yǔ)法
  • Map, Set, WeakMap,WeakSet的構(gòu)造器。為什么沒(méi)有Array?因?yàn)锳rray直接把它對(duì)象當(dāng)成元素了,但是有Array.from(iterable)。
  • Object.fromEntries(iterable) ,每次迭代結(jié)果應(yīng)該是一個(gè)對(duì)應(yīng)鍵值對(duì)的二元數(shù)組,與Map的迭代結(jié)果吻合,常有let obj = Object.fromEntries(map)實(shí)現(xiàn)從map到object的轉(zhuǎn)化。
  • promise.all(iterable)promist.race(iterable).

我認(rèn)為對(duì)這些方法的具體使用不該放在這里,如果使用過(guò)它們,自然了解,只需要記住它們對(duì)任何可迭代對(duì)象都是支持的。如果不認(rèn)識(shí)它們我也說(shuō)不完,你應(yīng)該一一學(xué)習(xí)去。

6、后記

到此這篇關(guān)于JavaScript可迭代對(duì)象詳細(xì)介紹的文章就介紹到這了,更多相關(guān)JS可迭代對(duì)象內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • JS函數(shù)的幾種定義方式分析

    JS函數(shù)的幾種定義方式分析

    這篇文章主要介紹了JS函數(shù)的幾種定義方式,實(shí)例分析了JavaScript四種函數(shù)定義方式及具體的使用技巧,需要的朋友可以參考下
    2015-12-12
  • JS+Canvas實(shí)現(xiàn)滿屏愛(ài)心和文字動(dòng)畫(huà)的制作

    JS+Canvas實(shí)現(xiàn)滿屏愛(ài)心和文字動(dòng)畫(huà)的制作

    Canvas?適合繪制大數(shù)據(jù)量圖形元素的圖表(如熱力圖、地理坐標(biāo)系或平行坐標(biāo)系上的大規(guī)模線圖或散點(diǎn)圖等),也適合實(shí)現(xiàn)某些視覺(jué)特效。本文就來(lái)利用Canvas實(shí)現(xiàn)滿屏愛(ài)心和文字動(dòng)畫(huà)的制作,感興趣的可以了解一下
    2022-11-11
  • 對(duì)layer彈出框中icon數(shù)字參數(shù)的說(shuō)明介紹

    對(duì)layer彈出框中icon數(shù)字參數(shù)的說(shuō)明介紹

    今天小編就為大家分享一篇對(duì)layer彈出框中icon數(shù)字參數(shù)的說(shuō)明介紹,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-09-09
  • JS 實(shí)現(xiàn)百度搜索功能

    JS 實(shí)現(xiàn)百度搜索功能

    這篇文章給大家介紹了js實(shí)現(xiàn)百度搜索功能,代碼分為html部分和css折疊樣式部分,具體實(shí)現(xiàn)代碼大家參考下本文
    2018-02-02
  • 淺談JavaScript中的屬性:如何遍歷屬性

    淺談JavaScript中的屬性:如何遍歷屬性

    下面小編就為大家?guī)?lái)一篇淺談JavaScript中的屬性:如何遍歷屬性。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-09-09
  • JavaScript雙向鏈表實(shí)現(xiàn)LRU緩存算法的示例代碼

    JavaScript雙向鏈表實(shí)現(xiàn)LRU緩存算法的示例代碼

    本文主要介紹了JavaScript雙向鏈表實(shí)現(xiàn)LRU緩存算法的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • JavaScript循環(huán)_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    JavaScript循環(huán)_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    這篇文章主要為大家詳細(xì)介紹了JavaScript循環(huán)的相關(guān)資料,JavaScript的兩種循環(huán)方式,一種是for循環(huán),另while一種是循環(huán)具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • JS中的算法與數(shù)據(jù)結(jié)構(gòu)之隊(duì)列(Queue)實(shí)例詳解

    JS中的算法與數(shù)據(jù)結(jié)構(gòu)之隊(duì)列(Queue)實(shí)例詳解

    這篇文章主要介紹了JS中的算法與數(shù)據(jù)結(jié)構(gòu)之隊(duì)列(Queue),結(jié)合實(shí)例形式詳細(xì)分析了javascript中隊(duì)列的概念、原理、定義及常見(jiàn)操作技巧,需要的朋友可以參考下
    2019-08-08
  • javascript將json格式數(shù)組下載為excel表格的方法

    javascript將json格式數(shù)組下載為excel表格的方法

    下面小編就為大家分享一篇javascript將json格式數(shù)組下載為excel表格的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2017-12-12
  • js中常用的Tab切換效果(推薦)

    js中常用的Tab切換效果(推薦)

    下面小編就為大家?guī)?lái)一篇js中常用的Tab切換效果(推薦)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧,祝大家游戲愉快哦
    2016-08-08

最新評(píng)論