JavaScript類陣列和可迭代物件的實現原理詳解

2022-06-09 14:01:13
本篇文章給大家帶來了關於的相關知識,其中主要介紹了關於類陣列和可迭代物件的實現原理,包括了把物件本身構造成迭代器、String的迭代器等等相關內容,下面一起來看一下吧,希望對大家有幫助。

【相關推薦:、】

可迭代物件(Iterable object)

陣列是一個特殊的物件,它和普通物件的區別不僅僅在於元素的順序存取、儲存。另外一個重要的區別是:陣列是可迭代的,也就是可以使用for ... of語句存取(迭代)所有的元素。

我們可以簡單的做一個小實驗:

let arr = [1,2,3,4,5]for(let val of arr){
    console.log(val)}

程式碼執行結果:

image-20220604080921048

以上程式碼就簡單的使用了陣列的迭代特性,我們在存取陣列元素的時候,不必使用元素的下標。

如果我們對一個普通物件使用for ... of語句會發生什麼呢?

let obj = {
    name:'xiaoming',
    age:12,}for(let para of obj){ //程式碼會報錯
    console.log(para)}

執行效果如下:

image-20220604081556714

這就證明普通的物件和陣列之間還有一個可迭代的差距,我們稱具備迭代功能的物件為可迭代物件

Symbol.iterator

如果我們希望一個物件可以迭代,必須為物件新增一個名為Symbol.iterator的方法(一個專門使物件可迭代的內建Symbol)。

方法作用包括:

  1. 當使用for ... of迴圈迭代物件時,就會呼叫Symbol.iterator方法,這個方法必須返回一個迭代器(一個有next()方法的物件)。
  2. 得到迭代器後,for ... of會不斷的呼叫迭代器的next()方法獲得下一個元素。
  3. next()方法返回的內容必須符合格式:{done:Boolean,value:any},當done:true時,迴圈結束,否則value就是下一個值。

迭代器:

迭代器是借鑑C++等語言的概念,迭代器的原理就像指標一樣,它指向資料集合中的某個元素,你可以獲取它指向的元素,也可以移動它以獲取其它元素。迭代器類似於陣列中下標的拓展,各種資料結構,如連結串列(List)、集合(Set)、對映(Map)都有與之對應的迭代器。

JS中的迭代器是專門為了遍歷這一操作設計的。每次獲取到的迭代器總是初始指向第一個元素,並且迭代器只有next()一種行為,直到獲取到資料集的最後一個元素。我們無法靈活移動迭代器的位置,所以,迭代器的任務,是按某種次序遍歷資料集中的元素

實現一個可迭代物件:

let obj = {
    from:1,
    to:5,}obj[Symbol.iterator] = function(){
    //返回一個迭代器
    return {
        current:this.from,
        last:this.to,
        next(){
            if(this.current<this.last){
                return {done:false,value:this.current++}
            }else{
                return {done:true}//迭代結束
            }
        }
    }}for(let para of obj){
    console.log(para)}

程式碼執行效果:

image-20220604083540285

注意,以上物件雖然可以進行迭代了,但是,迭代使用使用的材料並非物件,而是Symbol.iterator返回的迭代器(也是一個物件)。

把物件本身構造成迭代器

以上程式碼構造了一個內建函數Symbol.iterator(),這個函數返回了一個迭代器物件。我們還可以採用另外一種實現迭代器的方式:把物件本身做成迭代器:

let obj = {
    from:1,
    to:5,
    [Symbol.iterator](){
        this.current = this.from;
        return this;//返回物件本身
    },
    next(){//給物件新增一個next方法
        if(this.current<this.to){
            return {done:false,value:this.current++}
        }else{
            return {done:true}
        }
    }}for(let para of obj){
    console.log(para)}

程式碼執行效果和上面的圖片展示相同。

這麼做雖然程式碼更加簡潔了,但是由於並沒有新的可迭代物件產生,我們就沒有辦法同時執行兩個for ... of迴圈迭代同一個物件了,但是兩個並行的迭代在同一個物件上是非常罕見的。

我們可以總結可迭代物件的概念:

所謂可迭代物件,就是比普通物件多了一個名為Symbol.iterator方法的普通物件,這個方法返回一個迭代器。

或者,一個具備Symbol.iterator同時具備next方法的物件也是一個可迭代的物件。

String也是可迭代的

陣列和字串都是可以迭代的,我們可以很方便的使用for...of語句迭代陣列中的字元元素:

let str = '123'for(let c of str){
    console.log(c)}

這對於代理對(UTF-16擴充套件字元)同樣是有效的:

let str = '...'for(let c of str){
    console.log(c)}

執行效果如下:

image-20220604085545804

String的迭代器

並非只有for...of語句能夠使用迭代器,我們還可以顯式的呼叫迭代器:

let str = '12345'let itr = str[Symbol.iterator]()while(true){
    let result = itr.next()
    if(result.done)break;
    console.log(result.value)}

程式碼執行效果:

image-20220604085813686

以上程式碼執行了遍歷字串字元的操作,是不是覺得可迭代物件就沒有這麼神祕了!

類陣列物件和可迭代物件

類陣列和可迭代在遍歷功能上非常相似,都可以方便的方式內部元素,但是二者仍然有明顯的區別:

  1. iterable可迭代物件:實現了Symbol.iterator的物件;
  2. array-like類陣列物件:具有數位索引,並且有length屬性;

字串就是一個即使類陣列又是可迭代的物件。

可迭代和類陣列物件通常都不是陣列,如果我們想把一個可迭代或者類陣列物件轉為陣列,需要使用Array.from方法。

Array.from

使用Array.from將字串轉為陣列:

let str = '123'let arr = Array.from(str)console.log(arr)

程式碼執行效果如下:

image-20220604091552590

把自定義的類陣列物件轉為陣列:

let obj = {
    0:'0',
    1:'1',
    2:'2',
    length:3}let arr = Array.from(obj)console.log(arr)

程式碼執行結果:

image-20220604091736400

Array.from的完整語法:

Array.from(obj[, mapFunc, thisArg])

mapFunc方法會在生成陣列之前對每個可迭代或類陣列元素呼叫,如果mapFunc是一個成員方法,可以使用thisArg提供this指標。

舉個例子:

let str = '12345'let arr = Array.from(str,itm=>+itm)console.log(arr)

程式碼執行結果:

image-20220604092137378

這裡通過對映函數,將本應該生成字元陣列轉為數位陣列。

總結

  1. 可以使用for...of語法的物件被稱為可迭代物件
  2. 可迭代物件是在普通物件的基礎上實現了Symbol.iterator方法的物件
  3. Symbol.iterator方法返回了一個迭代器;
  4. 迭代器包含一個next方法,該方法返回下一個元素的值;
  5. next方法返回值需要滿足格式{done:Boolean,value:nextVal},當done:true時,迭代結束
  6. Array.from可以把類陣列和可迭代物件轉為陣列;

【相關推薦:、】

以上就是JavaScript類陣列和可迭代物件的實現原理詳解的詳細內容,更多請關注TW511.COM其它相關文章!