javascript 偽陣列實現方法

發表於2015-07-19

什麼是偽陣列

能通過Array.prototype.slice轉換為真正的陣列的帶有length屬性的物件。

這種物件有很多,比較特別的是arguments物件,還有像呼叫getElementsByTagName,document.childNodes之類的,它們都返回NodeList物件都屬於偽陣列。

我們可以通過Array.prototype.slice.call(fakeArray)將偽陣列轉變為真正的Array物件。

來看個示例:

slice 可以用來獲取陣列片段,它返回新陣列,不會修改原陣列。

示例中可以看到fakeArray被成功的轉換成了Array物件。也許大家對Array.prototype.slice.call這種寫法比較陌生,其實我們也可以通過[].slice.call這種形式實現同樣的效果,那為什麼我們要通過prototype的形式實現呢,答案是以prototype的形式執行程式效率更高,同樣程式碼也更加優美。

偽陣列的實現

我們來看一些特殊的用例

同樣fakeArray01和fakeArray02被轉換成了真正的陣列,但是陣列中的值都為undefined
檢視 V8 引擎 array.js 的原始碼,可以將 slice 的內部實現簡化為:

可以看出,slice 並不需要 this 為 array 型別,只需要有 length 屬性即可。並且 length 屬性可以不為 number 型別,當不能轉換為數值時,ToUnit32(this.length) 返回 0.
根據以上結論可以得出:fakeArray01被轉換成了lenth為2的陣列,其值都被初始化為undefined,fakeArray02被轉換成了length為0的陣列,自然訪問下標為1的元素返回undefined

IE的問題

針對於標準瀏覽器slice實現已經可以解釋所有的問題,但是IE在處理NodeList時出現了問題。IE中無法將NodeList轉換為真正的陣列,會出錯。這又是為什麼呢?嚴格說,在IE內部定義了一個抽象類Arraioid,Array和Arguments都繼承與此,所以可以用slice。但DOM物件是通過COM接入到JScript的,slice檢測的時候失效。

Jquery與偽陣列

Jquery內部大量運用了偽陣列。可以說整個Jquery物件,都是構建在偽陣列的基礎之上的,好讓我們來看一些Jquery的實際運用:

再簡單不過的程式了,好,讓我們來看一下其內部的實現原理:

最後,我們來解釋一下,程式的執行細節.但是在這之前,還得說一下關於Jquery的內部的一些東西。
用過Jquery的使用者應該都知道$()函式,它是Jquery的選擇器代表。我們可能通過$()函式去選取頁面中的元素(具體語法可引數Jquery幫助文件)。實際上當我們執行$()函式時,程式去執行上面列出的init方法,我們來看一下在呼叫$(document)時所發生的事件:

$(“body”)是同樣的道理,不再多說了。
我們知道Jquery裡所有的操作返回的都是Jquery物件,那我們如何得到其所對應的dom物件呢,Jquery為我們提供了一個get方法,這是專門用來從jquery物件中取得DOM物件用的,由此,便有了body.get(0),那為什麼又是get(0)而不是get()呢,因為Jquery的所有操作都是針對於陣列進行的。所以,在get方法裡,我們要傳一個下標值,來得到具體的元素。現在該看get方法的具體實現了:

關於偽陣列就到這吧,我想應該已經差不多了。
注:有機會的話,將來可能會出一個”超越Jquery”系列,專門分析Jquery內部執行細節。但是由於Jquery內部的有各種歪門邪道的手法還不是很理解,所以這是將來的問題了。

符合類陣列物件的兩條規則

  • 它們都有一個合法的 length 屬性(0 到 2**32 – 1 之間的正整數)。
  • length 屬性的值大於它們的最大索引(index)。

參考連結:

http://lifesinger.org/blog/2010/05/array-prototype-slice/ (已經失效)
http://segmentfault.com/a/1190000002648510

相關文章