JavaScript數(shù)組的進化
JavaScript數(shù)組在內(nèi)部實現(xiàn)上并不是連續(xù)的,而更類似于哈希映射或字典。這使得JavaScript數(shù)組有些像是一門B級語言,因為數(shù)組的實現(xiàn)方式并不合適。 為什么說JavaScript數(shù)組不是真正
JavaScript數(shù)組在內(nèi)部實現(xiàn)上并不是連續(xù)的,而更類似于哈希映射或字典。這使得JavaScript數(shù)組有些像是一門B級語言,因為數(shù)組的實現(xiàn)方式并不合適。
為什么說JavaScript數(shù)組不是真正的數(shù)組
數(shù)組是一串連續(xù)的內(nèi)存位置,用來保存某些值。重要的是要注意“連續(xù)”這個詞。下圖展示了數(shù)組在內(nèi)存中的存儲方式。一個包含4個元素的數(shù)組,每個元素占據(jù)4個字節(jié),總共占用16個字節(jié)的內(nèi)存空間。假設我們聲明了一個tinyInt arr[4],該數(shù)組在內(nèi)存中的地址從1201開始。當我們需要讀取arr[2]時,只需要進行數(shù)學計算,即1201 (2 * 4),然后從1209開始讀取即可。
JavaScript數(shù)組與真實數(shù)組的不同之處
JavaScript中的數(shù)據(jù)通過哈希映射實現(xiàn),可以使用不同的數(shù)據(jù)結(jié)構,如鏈表。因此,如果在JavaScript中聲明一個數(shù)組var arr new Array(4),計算機將生成類似上圖的結(jié)構。如果程序需要讀取arr[2],則需要從1201開始遍歷尋址。很明顯,數(shù)學計算比遍歷鏈表快,尤其對于較長的數(shù)組而言。這就是JavaScript數(shù)組與真實數(shù)組的區(qū)別。
JavaScript數(shù)組的進化
JavaScript語言本身也在不斷演化。從V8、SpiderMonkey到TC39以及日益增長的Web用戶群體,巨大的努力使JavaScript成為全球必備技術。當用戶基數(shù)龐大時,性能提升變得非常重要。
現(xiàn)代的JavaScript引擎會為數(shù)組分配連續(xù)的內(nèi)存,前提是數(shù)組是同質(zhì)的(所有元素類型相同)。優(yōu)秀的程序員通常會保證數(shù)組的同質(zhì)性,以便JIT(即時編譯器)能夠使用C編譯器風格的方法來讀取元素。如果代碼編寫得不太糟糕,JavaScript Array對象在幕后仍然以真正的數(shù)組形式存在,這對現(xiàn)代的JavaScript開發(fā)者來說非常重要。
隨著ES2015/ES6的推出,數(shù)組也有了更多的演進。TC39決定引入類型化數(shù)組(Typed Arrays),于是我們有了ArrayBuffer。ArrayBuffer提供一塊連續(xù)的內(nèi)存,可以隨意操作。直接操作內(nèi)存可能過于復雜和底層,因此產(chǎn)生了處理ArrayBuffer的視圖(View)。目前已經(jīng)有一些可用的視圖,未來還會有更多加入。
了解更多關于類型化數(shù)組的知識
如果想要了解更多關于類型化數(shù)組(Typed Arrays)的知識,請訪問MDN文檔。高性能、高效率的類型化數(shù)組在WebGL之后被引入。WebGL開發(fā)者面臨著處理二進制數(shù)據(jù)的性能問題。使用SharedArrayBuffer可以在多個Web Worker進程之間共享數(shù)據(jù),提升性能。
舊式數(shù)組 vs 類型化數(shù)組:性能
前面已經(jīng)探討了JavaScript數(shù)組的演進,現(xiàn)在我們來測試現(xiàn)代數(shù)組帶來的性能收益有多大。
舊式數(shù)組和ArrayBuffer的性能幾乎相同,現(xiàn)代編譯器已經(jīng)足夠智能,可以將元素類型相同的傳統(tǒng)數(shù)組在內(nèi)部轉(zhuǎn)換成內(nèi)存連續(xù)的數(shù)組。第一個例子就是這樣。盡管使用了new Array(LIMIT),數(shù)組實際上仍然以現(xiàn)代數(shù)組的形式存在。
接下來,我們將修改第一個例子,將數(shù)組改為異構型(元素類型不完全一致),看看是否存在性能差異。
修改發(fā)生在第3行,添加一條語句將數(shù)組變?yōu)楫悩嬵愋?。其余代碼保持不變。結(jié)果顯示性能差異明顯,慢了22倍。
類型化數(shù)組的引入
類型化數(shù)組的引入是JavaScript發(fā)展歷程中的一大步。Int8Array、Uint8Array、Uint8ClampedArray、Int16Array、Uint16Array、Int32Array、Uint32Array、Float32Array、Float64Array等都是類型化數(shù)組的視圖,它們使用原生字節(jié)序(與本機相同)。我們還可以使用DataView創(chuàng)建自定義的視圖窗口。希望未來會有更多的DataView庫幫助我們輕松操作ArrayBuffer。
JavaScript數(shù)組的演進非常不錯?,F(xiàn)在它們速度快、效率高、健壯,而且在內(nèi)存分配方面也足夠智能。