【相關推薦:、】
陣列是一個特殊的物件,它和普通物件的區別不僅僅在於元素的順序存取、儲存。另外一個重要的區別是:陣列是可迭代的,也就是可以使用for ... of
語句存取(迭代)所有的元素。
我們可以簡單的做一個小實驗:
let arr = [1,2,3,4,5]for(let val of arr){ console.log(val)}
程式碼執行結果:
以上程式碼就簡單的使用了陣列的迭代特性,我們在存取陣列元素的時候,不必使用元素的下標。
如果我們對一個普通物件使用for ... of
語句會發生什麼呢?
let obj = { name:'xiaoming', age:12,}for(let para of obj){ //程式碼會報錯 console.log(para)}
執行效果如下:
這就證明普通的物件和陣列之間還有一個可迭代的差距,我們稱具備迭代功能的物件為可迭代物件。
如果我們希望一個物件可以迭代,必須為物件新增一個名為Symbol.iterator
的方法(一個專門使物件可迭代的內建Symbol
)。
方法作用包括:
for ... of
迴圈迭代物件時,就會呼叫Symbol.iterator
方法,這個方法必須返回一個迭代器(一個有next()
方法的物件)。for ... of
會不斷的呼叫迭代器的next()
方法獲得下一個元素。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)}
程式碼執行效果:
注意,以上物件雖然可以進行迭代了,但是,迭代使用使用的材料並非物件,而是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
方法的物件也是一個可迭代的物件。
陣列和字串都是可以迭代的,我們可以很方便的使用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)}
執行效果如下:
並非只有for...of
語句能夠使用迭代器,我們還可以顯式的呼叫迭代器:
let str = '12345'let itr = str[Symbol.iterator]()while(true){ let result = itr.next() if(result.done)break; console.log(result.value)}
程式碼執行效果:
以上程式碼執行了遍歷字串字元的操作,是不是覺得可迭代物件就沒有這麼神祕了!
類陣列和可迭代在遍歷功能上非常相似,都可以方便的方式內部元素,但是二者仍然有明顯的區別:
iterable
可迭代物件:實現了Symbol.iterator
的物件;array-like
類陣列物件:具有數位索引,並且有length
屬性;字串就是一個即使類陣列又是可迭代的物件。
可迭代和類陣列物件通常都不是陣列,如果我們想把一個可迭代或者類陣列物件轉為陣列,需要使用Array.from
方法。
使用Array.from
將字串轉為陣列:
let str = '123'let arr = Array.from(str)console.log(arr)
程式碼執行效果如下:
把自定義的類陣列物件轉為陣列:
let obj = { 0:'0', 1:'1', 2:'2', length:3}let arr = Array.from(obj)console.log(arr)
程式碼執行結果:
Array.from
的完整語法:
Array.from(obj[, mapFunc, thisArg])
mapFunc
方法會在生成陣列之前對每個可迭代或類陣列元素呼叫,如果mapFunc
是一個成員方法,可以使用thisArg
提供this
指標。
舉個例子:
let str = '12345'let arr = Array.from(str,itm=>+itm)console.log(arr)
程式碼執行結果:
這裡通過對映函數,將本應該生成字元陣列轉為數位陣列。
for...of
語法的物件被稱為可迭代物件Symbol.iterator
方法的物件Symbol.iterator
方法返回了一個迭代器;next
方法,該方法返回下一個元素的值;next
方法返回值需要滿足格式{done:Boolean,value:nextVal}
,當done:true
時,迭代結束Array.from
可以把類陣列和可迭代物件轉為陣列;
【相關推薦:、】
以上就是JavaScript類陣列和可迭代物件的實現原理詳解的詳細內容,更多請關注TW511.COM其它相關文章!