前面的話
??定型數(shù)組是一種用于處理數(shù)值類(lèi)型(正如其名,不是所有類(lèi)型)數(shù)據(jù)的專(zhuān)用數(shù)組准浴,最早是在
WebGL
中使用的西傀,WebGL
是OpenGL ES 2.0
的移植版斤寇,在Web
頁(yè)面中通過(guò)<canvas>
元素來(lái)呈現(xiàn)它。定型數(shù)組也被一同移植而來(lái)拥褂,其可為JS
提供快速的按位運(yùn)算娘锁。本文將詳細(xì)介紹ES6
定型數(shù)組
概述
??在
JS
中,數(shù)字是以64位浮點(diǎn)格式存儲(chǔ)的饺鹃,并按需轉(zhuǎn)換為32位整數(shù)莫秆,所以算術(shù)運(yùn)算非常慢,無(wú)法滿足WebGL
的需求悔详。因此在ES6
中引入定型數(shù)組來(lái)解決這個(gè)問(wèn)題镊屎,并提供更高性能的算術(shù)運(yùn)算。所謂定型數(shù)組茄螃,就是將任何數(shù)字轉(zhuǎn)換為一個(gè)包含數(shù)字比特的數(shù)組缝驳,隨后就可以通過(guò)我們熟悉的JS
數(shù)組方法來(lái)進(jìn)一步處理
??
ES6
采用定型數(shù)組作為語(yǔ)言的正式格式來(lái)確保更好的跨JS
引擎兼容性以及與JS
數(shù)組的互操作性。盡管ES6
版本的定型數(shù)組與WebGL
中的不一樣归苍,但是仍保留了足夠的相似之處用狱,這使得ES6
版本可以基于WebGL
版本演化而不至于走向完全分化
【數(shù)值數(shù)據(jù)類(lèi)型】
JS
數(shù)字按照IEEE 754
標(biāo)準(zhǔn)定義的格式存儲(chǔ),也就是用64個(gè)比特來(lái)存儲(chǔ)一個(gè)浮點(diǎn)形式的數(shù)字拼弃。這個(gè)格式用于表示JS
中的整數(shù)及浮點(diǎn)數(shù)夏伊,兩種格式間經(jīng)常伴隨著數(shù)字改變發(fā)生相互轉(zhuǎn)換。定型數(shù)組支持存儲(chǔ)和操作以下8種不同的數(shù)值類(lèi)型
無(wú)符號(hào)的8位整數(shù)
(uint8)
有符號(hào)的16位整數(shù)(int16)
無(wú)符號(hào)的16位整數(shù)(uint16)
有符號(hào)的32位整數(shù)(int32)
無(wú)符號(hào)的32位整數(shù)(uint32)
32位浮點(diǎn)數(shù)(float32)
64位浮點(diǎn)數(shù)(float64)
如果用普通的JS數(shù)字來(lái)存儲(chǔ)8位整數(shù)吻氧,會(huì)浪費(fèi)整整56個(gè)比特署海,這些比特原本可以存儲(chǔ)其他8位整數(shù)或小于56比特的數(shù)字。這也正是定型數(shù)組的一個(gè)實(shí)際用例医男,即更有效地利用比特
所有與定型數(shù)組有關(guān)的操作和對(duì)象都集中在這8個(gè)數(shù)據(jù)類(lèi)型上,但是在使用它們之前捻勉,需要?jiǎng)?chuàng)建一個(gè)數(shù)組緩沖區(qū)存儲(chǔ)這些數(shù)據(jù)
【數(shù)組緩沖區(qū)】
數(shù)組緩沖區(qū)是所有定型數(shù)組的根基镀梭,它是一段可以包含特定數(shù)量字節(jié)的內(nèi)存地址。創(chuàng)建數(shù)組緩沖區(qū)的過(guò)程類(lèi)似于在
C
語(yǔ)言中調(diào)用malloc()
來(lái)分配內(nèi)存踱启,只是不需指明內(nèi)存塊所包含的數(shù)據(jù)類(lèi)型报账。可以通過(guò)ArrayBuffer
構(gòu)造函數(shù)來(lái)創(chuàng)建數(shù)組緩沖區(qū)
let buffer = New ArrayBuffer(10) // 分配10字節(jié)
- 調(diào)用構(gòu)造函數(shù)時(shí)傳入數(shù)組緩沖區(qū)應(yīng)含的比特?cái)?shù)量即可埠偿,此示例中的這條語(yǔ)句創(chuàng)建了一個(gè)10字節(jié)長(zhǎng)度的數(shù)組緩沖區(qū)透罢。創(chuàng)建完成后,可以通過(guò)
byteLength
屬性查看緩沖區(qū)中的比特?cái)?shù)量
let buffer = new ArrayBuffer(10); // 分配了 10 個(gè)字節(jié)
console.log(buffer.byteLength); // 10
- 可以通過(guò)
slice()
方法分割已有數(shù)組緩沖區(qū)來(lái)創(chuàng)建一個(gè)新的冠蒋,這個(gè)slice()
方法與數(shù)組上的slice()
方法很像:傳入開(kāi)始索引和結(jié)束索引作為參數(shù)羽圃,然后返回一個(gè)新的ArrayBuffer
實(shí)例,新實(shí)例由原始數(shù)組緩沖區(qū)的切片組成
let buffer = new ArrayBuffer(10); // 分配了 10 個(gè)字節(jié)
let buffer2 = buffer.slice(4, 6);
console.log(buffer2.byteLength); // 2
在這段代碼中抖剿,
buffer2
創(chuàng)建從索引4和索引5提取的字節(jié)朽寞,此處slice()
方法的調(diào)用與數(shù)組版本的類(lèi)似识窿,傳入的第二個(gè)參數(shù)不包含在最終結(jié)果中當(dāng)然,僅創(chuàng)建存儲(chǔ)單元用途不大脑融,除非能夠?qū)?shù)據(jù)寫(xiě)到那個(gè)單元中喻频,還需要?jiǎng)?chuàng)建一個(gè)視圖來(lái)實(shí)現(xiàn)寫(xiě)入的功能
[注意]數(shù)組緩沖區(qū)包含的實(shí)際字節(jié)數(shù)量在創(chuàng)建時(shí)就已確定,可以修改緩沖區(qū)內(nèi)的數(shù)據(jù)肘迎,但是不能改變緩沖區(qū)的尺寸大小
視圖操作
數(shù)組緩沖區(qū)是內(nèi)存中的一段地址甥温,視圖是用來(lái)操作內(nèi)存的接口。視圖可以操作數(shù)組緩沖區(qū)或緩沖區(qū)字節(jié)的子集妓布,并按照其中一種數(shù)值型數(shù)據(jù)類(lèi)型來(lái)讀取和寫(xiě)入數(shù)據(jù)姻蚓。
DataView
類(lèi)型是一種通用的數(shù)組緩沖區(qū)視圖,其支持所有8種數(shù)值型數(shù)據(jù)類(lèi)型,要使用DataView
秋茫,首先要?jiǎng)?chuàng)建一個(gè)ArrayBuffer
實(shí)例史简,然后用這個(gè)實(shí)例來(lái)創(chuàng)建新的Dataview
let buffer = new ArrayBuffer(10),
view = new DataView(buffer);
- 在此示例中的
view
對(duì)象可以訪問(wèn)緩沖區(qū)中所有10字節(jié)。如果提供一個(gè)表示比特偏移量的數(shù)值肛著,那么可以基于緩沖區(qū)的其中一部分來(lái)創(chuàng)建視圖圆兵,DataView
將默認(rèn)選取從偏移值開(kāi)始到緩沖區(qū)末尾的所有比特。如果額外提供一個(gè)表示選取比特?cái)?shù)量的可選參數(shù)枢贿,DataView
則從偏移位置后選取該數(shù)量的比特
let buffer = new ArrayBuffer(10),
view = new DataView(buffer, 5, 2); // 包含位置 5 與位置 6 的字節(jié)
- 這里的
view
只能操作位于索引5和索引6的字節(jié)殉农。通過(guò)這種方法,可以基于同一個(gè)數(shù)組緩沖區(qū)創(chuàng)建多個(gè)view
局荚,因而可以為應(yīng)用申請(qǐng)一整塊獨(dú)立的內(nèi)存地址超凳,而不是當(dāng)需要空間時(shí)再動(dòng)態(tài)分配
【獲取視圖信息】
可以通過(guò)以下幾種只讀屬性來(lái)獲取視圖的信息
buffer
視圖綁定的數(shù)組緩沖區(qū)
byteOffset DataView
構(gòu)造函數(shù)的第二個(gè)參數(shù),默認(rèn)是0耀态,只有傳入?yún)?shù)時(shí)才有值
byteLength DataView
構(gòu)造函數(shù)的第三個(gè)參數(shù)轮傍,默認(rèn)是緩沖區(qū)的長(zhǎng)度byteLength</pre>
??通過(guò)這些屬性,可以查看視圖正在操作緩沖區(qū)的哪一部分
let buffer = new ArrayBuffer(10),
view1 = new DataView(buffer), // 包含所有字節(jié)
view2 = new DataView(buffer, 5, 2); // 包含位置 5 與位置 6 的字節(jié)
console.log(view1.buffer === buffer); // true
console.log(view2.buffer === buffer); // true
console.log(view1.byteOffset); // 0
console.log(view2.byteOffset); // 5
console.log(view1.byteLength); // 10
console.log(view2.byteLength); // 2
- 這段代碼一共創(chuàng)建了兩個(gè)視圖首装,
view1
覆蓋了整個(gè)數(shù)組緩沖區(qū)创夜,view2
只操作其中的一小部分。由于這些視圖都是基于相同的數(shù)組緩沖區(qū)創(chuàng)建的仙逻,因此它們具有相同的buffer
屬性驰吓,但每個(gè)視圖的byteOffset
和byteLength
屬性又互不相同,這兩個(gè)屬性的值取決于視圖操作數(shù)組緩沖區(qū)的哪一部分
當(dāng)然系奉,只從內(nèi)存讀取信息不是很有用檬贰,需要同時(shí)在內(nèi)存中讀寫(xiě)數(shù)據(jù)才能物盡其用
【讀取和寫(xiě)入數(shù)據(jù)】
JS
有8種數(shù)值型數(shù)據(jù)類(lèi)型,對(duì)于其中的每一種缺亮,都能在DataView
的原型上找到相應(yīng)的在數(shù)組緩沖區(qū)中寫(xiě)入數(shù)據(jù)和讀取數(shù)據(jù)的方法翁涤。這些方法名都以set
或get
打頭,緊跟著的是每一種數(shù)據(jù)類(lèi)型的縮寫(xiě)。例如迷雪,以下這個(gè)列表是用于讀取和寫(xiě)入int8
和unit8
類(lèi)型數(shù)據(jù)的方法
getInt8(byteOffset,littleEndian)
讀取位于byteOffset
后的int8
類(lèi)型數(shù)據(jù)
setInt8(byteOffset, value, littleEndian)
在byteOffset
處寫(xiě)入int8
類(lèi)型數(shù)據(jù)
getUint8(byteOffset, littleEndian)
讀取位于byteOffset
后的uint8
類(lèi)型數(shù)據(jù)
setUint8(byteOffset, value, littleEndian)
在byteOffset
處寫(xiě)入uint8
類(lèi)型數(shù)據(jù)
-
get
方法接受兩個(gè)參數(shù):讀取數(shù)據(jù)時(shí)偏移的字節(jié)數(shù)量和一個(gè)可選的布爾值限书,表示是否按照小端序進(jìn)行讀取(小端序是指最低有效字節(jié)位于字節(jié)0的字節(jié)順序)。set
方法接受三個(gè)參數(shù):寫(xiě)入數(shù)據(jù)時(shí)偏移的比特?cái)?shù)量章咧、寫(xiě)入的值和一個(gè)可選的布爾值倦西,表示是否按照小端序格式存儲(chǔ)。盡管這里只展示了用于8位值的方法赁严,但是有一些相同的方法也可用于操作16或32位的值扰柠,只需將每一個(gè)方法名中的8替換為16或32即可。除所有整數(shù)方法外疼约,DataView
同樣支持以下讀取和寫(xiě)入浮點(diǎn)數(shù)的方法
getFloat32(byteOffset, littleEndian)
讀取位于byteOffset
后的float32
類(lèi)型數(shù)據(jù)
setFloat32(byteOffset,value,littleEndian)
在byteOffset
處寫(xiě)入float32
類(lèi)型數(shù)據(jù)
getFloat64(byteOffset,littleEndian)
讀取位于byteOffset
后的float64
類(lèi)型數(shù)據(jù)
setFloat64(byteOffset,value,littleEndian)
在byteOffset
處寫(xiě)入float64
類(lèi)型數(shù)據(jù)
以下示例分別展示了set
和get
方法的實(shí)際運(yùn)用
let buffer = new ArrayBuffer(2),
view = new DataView(buffer);
view.setInt8(0, 5);
view.setInt8(1, -1);
console.log(view.getInt8(0)); // 5
console.log(view.getInt8(1)); // -1
這段代碼使用兩字節(jié)數(shù)組緩沖器來(lái)存儲(chǔ)兩個(gè)
int8
類(lèi)型的值卤档,分別位于偏移0和1,每個(gè)值都橫跨一整個(gè)字節(jié)(8個(gè)比特)隨后通過(guò)getlnt8()
方法將這些值從它們所在的位置提取出來(lái)視圖是獨(dú)立的程剥,無(wú)論數(shù)據(jù)之前是通過(guò)何種方式存儲(chǔ)的劝枣,都可在任意時(shí)刻讀取或?qū)懭肴我飧袷降臄?shù)據(jù)。舉個(gè)例子织鲸,寫(xiě)入兩個(gè)
int8
類(lèi)型的值舔腾,然后使用int16
類(lèi)型的方法也可以從緩沖區(qū)中讀出這些值
let buffer = new ArrayBuffer(2),
view = new DataView(buffer);
view.setInt8(0, 5);
view.setInt8(1, -1);
console.log(view.getInt16(0)); // 1535
console.log(view.getInt8(0)); // 5
console.log(view.getInt8(1)); // -1
- 調(diào)用
view.getInt16(0)
時(shí)會(huì)讀取視圖中的所有字節(jié)并將其解釋為數(shù)字1535。如下所示搂擦,由每一行的setInt8()
方法執(zhí)行后數(shù)組緩沖區(qū)的變化稳诚,可以理解為何會(huì)得到這個(gè)結(jié)果
new ArrayBuffer(2) 0000000000000000
view.setInt8(0, 5); 0000010100000000
view.setInt8(1, -1); 0000010111111111
起初,數(shù)組緩沖區(qū)所有16個(gè)比特的值都是0瀑踢,通過(guò)
setInt8()
方法將數(shù)字5寫(xiě)入第一個(gè)字節(jié)扳还,其中兩個(gè)數(shù)字0會(huì)變?yōu)閿?shù)字1(8比特表示下的5是00000101)將-1寫(xiě)入第二個(gè)字節(jié),所有比特都會(huì)變?yōu)?橱夭,這也是-1的二進(jìn)制補(bǔ)碼表示氨距。第一次調(diào)用setInt8()
后,數(shù)組緩沖區(qū)共包含16個(gè)比特棘劣,getInt16()
會(huì)將這些比特讀作一個(gè)16位整型數(shù)字俏让,也就是十進(jìn)制的1535當(dāng)混合使用不同數(shù)據(jù)類(lèi)型時(shí),
DataView
對(duì)象是一個(gè)完美的選擇呈础,然而,如果只使用某個(gè)特定的數(shù)據(jù)類(lèi)型橱健,那么特定類(lèi)型的視圖則是更好的選擇
【定型數(shù)組是視圖】
ES6
定型數(shù)組實(shí)際上是用于數(shù)組緩沖區(qū)的特定類(lèi)型的視圖而钞,可以強(qiáng)制使用特定的數(shù)據(jù)類(lèi)型,而不是使用通用的DataView
對(duì)象來(lái)操作數(shù)組緩沖區(qū)拘荡。8個(gè)特定類(lèi)型的視圖對(duì)應(yīng)于8種數(shù)值型數(shù)據(jù)類(lèi)型臼节,uint8
的值還有其他選擇
“構(gòu)造器名稱(chēng)”一列列舉了幾個(gè)定型數(shù)組的構(gòu)造函數(shù),其他列描述了每一個(gè)定型數(shù)組可包含的數(shù)據(jù)。
Uint8ClampedArray
與uint8Array
大致相同网缝,唯一的區(qū)別在于數(shù)組緩沖區(qū)中的值如果小于0或大于255巨税,uint8ClampedArray
會(huì)分別將其轉(zhuǎn)換為0或255,例如粉臊,-1會(huì)變?yōu)?草添,300會(huì)變?yōu)?55
定型數(shù)組操作只能在特定的數(shù)據(jù)類(lèi)型上進(jìn)行,例如扼仲,所有
Int8Array
的操作都使用int8
類(lèi)型的值远寸。定型數(shù)組中元素的尺寸也取決于數(shù)組的類(lèi)型,Int8Array
中的元素占一個(gè)字節(jié)屠凶,而Float64Array
中的每個(gè)元素占8字節(jié)驰后。所幸的是,可以像正常數(shù)組一樣通過(guò)數(shù)值型索引來(lái)訪問(wèn)元素矗愧,從而避免了調(diào)用DataView
的set
和get
方法時(shí)的尷尬場(chǎng)面
【創(chuàng)建特定類(lèi)型的視圖】
定型數(shù)組構(gòu)造函數(shù)可以接受多種類(lèi)型的參數(shù)灶芝,所以可以通過(guò)多種方法來(lái)創(chuàng)建定型數(shù)組。首先唉韭,可以傳入DataView構(gòu)造函數(shù)可接受的參數(shù)來(lái)創(chuàng)建新的定型數(shù)組夜涕,分別是數(shù)組緩沖區(qū)淌实、可選的比特偏移量哼拔、可選的長(zhǎng)度值
let buffer = new ArrayBuffer(10),
view1 = new Int8Array(buffer),
view2 = new Int8Array(buffer, 5, 2);
console.log(view1.buffer === buffer); // true
console.log(view2.buffer === buffer); // true
console.log(view1.byteOffset); // 0
console.log(view2.byteOffset); // 5
console.log(view1.byteLength); // 10
console.log(view2.byteLength); // 2
在這段代碼中,兩個(gè)視圖均是通過(guò)
buffer
生成的Int8Array
實(shí)例,view1
和view2
有相同的buffer
墩划、byteOffset
和byteLength
屬性春塌,DataView
的實(shí)例包含這三種屬性晓避。當(dāng)你使用DataView
時(shí),只要希望只處理一種數(shù)值類(lèi)型只壳,總是很容易切換到相應(yīng)的定型數(shù)組創(chuàng)建定型數(shù)組的第二種方法是調(diào)用構(gòu)造函數(shù)時(shí)傳入一個(gè)數(shù)字俏拱。這個(gè)數(shù)字表示分配給數(shù)組的元素?cái)?shù)量(不是比特?cái)?shù)量),構(gòu)造函數(shù)將創(chuàng)建一個(gè)新的緩沖區(qū)吼句,并按照數(shù)組元素的數(shù)量來(lái)分配合理的比特?cái)?shù)量锅必,通過(guò)
length
屬性可以訪問(wèn)數(shù)組中的元素?cái)?shù)量
let ints = new Int16Array(2),
floats = new Float32Array(5);
console.log(ints.byteLength); // 4
console.log(ints.length); // 2
console.log(floats.byteLength); // 20
console.log(floats.length); // 5
ints
數(shù)組創(chuàng)建時(shí)含有兩個(gè)空元素,每個(gè)16比特整型值需要兩個(gè)字節(jié)惕艳,因而分配了4字節(jié)給該數(shù)組搞隐;floats
數(shù)組創(chuàng)建時(shí)含有5個(gè)空元素,每個(gè)元素占4字節(jié)远搪,所以共需要20字節(jié)劣纲。在這兩種情況下,如果要訪問(wèn)新創(chuàng)建的緩沖區(qū)谁鳍,則可以通過(guò)buffer
屬性來(lái)實(shí)現(xiàn)
[注意]調(diào)用定型數(shù)組的構(gòu)造函數(shù)時(shí)如果不傳參數(shù)癞季,會(huì)按照傳入0來(lái)處理劫瞳,這樣由于緩沖區(qū)沒(méi)有分配到任何比特,因而創(chuàng)建的定型數(shù)組不能用來(lái)保存數(shù)據(jù)
- 第三種創(chuàng)建定型數(shù)組的方法是調(diào)用構(gòu)造函數(shù)時(shí)绷柒,將以下任一對(duì)象作為唯一的參數(shù)傳入
1志于、一個(gè)定型數(shù)組
該數(shù)組中的每個(gè)元素會(huì)作為新的元素被復(fù)制到新的定型數(shù)組中。例如废睦,如果將一個(gè)
int8
數(shù)組傳入到Int16Array
構(gòu)造函數(shù)中伺绽,int8
的值會(huì)被復(fù)制到一個(gè)新的int16
數(shù)組中,新的定型數(shù)組使用新的數(shù)組緩沖區(qū)
2郊楣、一個(gè)可迭代對(duì)象
對(duì)象的迭代器會(huì)被調(diào)用憔恳,通過(guò)檢索所有條目來(lái)選取插入到定型數(shù)組的元素,如果所有元素都是不適用于該視圖類(lèi)型的無(wú)效類(lèi)型净蚤,構(gòu)造函數(shù)將會(huì)拋出一個(gè)錯(cuò)誤
3钥组、一個(gè)數(shù)組
數(shù)組中的元素會(huì)被復(fù)制到一個(gè)新的定型數(shù)組中,如果所有元素都是不適用于該視圖類(lèi)型的無(wú)效類(lèi)型今瀑,構(gòu)造函數(shù)將會(huì)拋出一個(gè)錯(cuò)誤
4程梦、一個(gè)類(lèi)數(shù)組對(duì)象
與傳入數(shù)組的行為一致
在每個(gè)示例中,新創(chuàng)建的定型數(shù)組的數(shù)據(jù)均取自源對(duì)象橘荠,這在用一些值初始化定型數(shù)組時(shí)尤為有用
let ints1 = new Int16Array([25, 50]),
ints2 = new Int32Array(ints1);
console.log(ints1.buffer === ints2.buffer); // false
console.log(ints1.byteLength); // 4
console.log(ints1.length); // 2
console.log(ints1[0]); // 25
console.log(ints1[1]); // 50
console.log(ints2.byteLength); // 8
console.log(ints2.length); // 2
console.log(ints2[0]); // 25
console.log(ints2[1]); // 50
- 在此示例中創(chuàng)建了一個(gè)
Int16Array
并用含兩個(gè)值的數(shù)組進(jìn)行初始化屿附,然后用Int16Array
作為參數(shù)創(chuàng)建一個(gè)Int32Arpay
,由于兩個(gè)定型數(shù)組的緩沖區(qū)完全獨(dú)立哥童,因此值25和50從ints1被復(fù)制到了ints2
挺份。在兩個(gè)定型數(shù)組中有相同的數(shù)字,只是ints2
用8字節(jié)來(lái)表示數(shù)據(jù)贮懈,而ints1
只用4字節(jié)
相同點(diǎn)
定型數(shù)組和普通數(shù)組有幾個(gè)相似之處匀泊,在許多情況下可以按照普通數(shù)組的使用方式去使用定型數(shù)組。例如朵你,通過(guò)
length
屬性可以查看定型數(shù)組中含有的元素?cái)?shù)量各聘,通過(guò)數(shù)值型索引可以直接訪問(wèn)定型數(shù)組中的元素
let ints = new Int16Array([25, 50]);
console.log(ints.length); // 2
console.log(ints[0]); // 25
console.log(ints[1]); // 50
ints[0] = 1;
ints[1] = 2;
console.log(ints[0]); // 1
console.log(ints[1]); // 2
- 在這段代碼中,新創(chuàng)建的
Int16Array
中有兩個(gè)元素抡医,這些元素均通過(guò)數(shù)值型索引來(lái)被讀取和寫(xiě)入躲因,那些值會(huì)自動(dòng)儲(chǔ)存并轉(zhuǎn)換成int16
類(lèi)型的值。當(dāng)然忌傻,定型數(shù)組與普通數(shù)組還有其他相似之處
[注意]可以修改length
屬性來(lái)改變普通數(shù)組的大小大脉,而定型數(shù)組的length
屬性是一個(gè)不可寫(xiě)屬性,所以不能修改定型數(shù)組的大小水孩,如果嘗試修改這個(gè)值镰矿,在非嚴(yán)格模式下會(huì)直接忽略該操作,在嚴(yán)格模式下會(huì)拋出錯(cuò)誤
【通用方法】
定型數(shù)組也包括許多在功能上與普通數(shù)組方法等效的方法荷愕,以下方法均可用于定型數(shù)組
copyWithin()
entries()
fill()
filter()
find()
findIndex()
forEach()
indexOf()
join()
keys()
lastIndexOf()
map()
reduce()
reduceRight()
reverse()
slice()
some()
sort()
values()
- 盡管這些方法與Array.prototype中的很像衡怀,但并非完全一致,定型數(shù)組中的方法會(huì)額外檢查數(shù)值類(lèi)型是否安全安疗,也會(huì)通過(guò)Symbol.species確認(rèn)方法的返回值是定型數(shù)組而非普通數(shù)組
let ints = new Int16Array([25, 50]),
mapped = ints.map(v => v * 2);
console.log(mapped.length); // 2
console.log(mapped[0]); // 50
console.log(mapped[1]); // 100
console.log(mapped instanceof Int16Array); // true
- 這段代碼使用
map()
方法創(chuàng)建一個(gè)存放整數(shù)的新數(shù)組抛杨,并通過(guò)map()
方法將數(shù)組中的每個(gè)值乘以2,最后返回一個(gè)新的Int16Array
類(lèi)型的數(shù)組
【相同的迭代器】
定型數(shù)組與普通數(shù)組有3個(gè)相同的迭代器荐类,分別是
entries()
方法怖现、keys()
方法和values()
方法,這意味著可以把定型數(shù)組當(dāng)作普通數(shù)組一樣來(lái)使用展開(kāi)運(yùn)算符玉罐、for-of
循環(huán)
let ints = new Int16Array([25, 50]),
intsArray = [...ints];
console.log(intsArray instanceof Array); // true
console.log(intsArray[0]); // 25
console.log(intsArray[1]); // 50
- 這段代碼創(chuàng)建了一個(gè)名為
intsArray
的新數(shù)組屈嗤,包含與定型數(shù)組ints
相同的數(shù)據(jù)。展開(kāi)運(yùn)算符能夠?qū)⒖傻鷮?duì)象轉(zhuǎn)換為普通數(shù)組吊输,也能將定型數(shù)組轉(zhuǎn)換為普通數(shù)組
【of()方法和from()方法】
所有定型數(shù)組都含有靜態(tài)
of()
方法和from()
方法饶号,運(yùn)行效果分別與Array.of()
方法和Array.from()
方法相似,區(qū)別是定型數(shù)組的方法返回定型數(shù)組季蚂,而普通數(shù)組的方法返回普通數(shù)組
let ints = Int16Array.of(25, 50),
floats = Float32Array.from([1.5, 2.5]);
console.log(ints instanceof Int16Array); // true
console.log(floats instanceof Float32Array); // true
console.log(ints.length); // 2
console.log(ints[0]); // 25
console.log(ints[1]); // 50
console.log(floats.length); // 2
console.log(floats[0]); // 1.5
console.log(floats[1]); // 2.5
- 在此示例中茫船,
of()
方法和from()
方法分別創(chuàng)建Int16Array
和Float32Array
,通過(guò)這些方法可以確保定型數(shù)組的創(chuàng)建過(guò)程如普通數(shù)組一樣簡(jiǎn)單
不同點(diǎn)
定型數(shù)組與普通數(shù)組最重要的差別是:定型數(shù)組不是普通數(shù)組扭屁。它不繼承自
Array
算谈,通過(guò)Array.isArray()
方法檢查定型數(shù)組返回的是false
let ints = new Int16Array([25, 50]);
console.log(ints instanceof Array); // false
console.log(Array.isArray(ints)); // false
- 由于變量
ints
是一個(gè)定型數(shù)組,因此它既不是Array
的實(shí)例料滥,也不能被認(rèn)作是一個(gè)數(shù)組然眼。做此區(qū)分很重要,因?yàn)楸M管定型數(shù)組與普通數(shù)組相似葵腹,但二者在很多方面的行為并不相同
【行為差異】
- 當(dāng)操作普通數(shù)組時(shí)高每,其可以變大變小,但定型數(shù)組卻始終保持相同的尺寸礁蔗。給定型數(shù)組中不存在的數(shù)值索引賦值會(huì)被忽略觉义,而在普通數(shù)組中就可以
let ints = new Int16Array([25, 50]);
console.log(ints.length); // 2
console.log(ints[0]); // 25
console.log(ints[1]); // 50
ints[2] = 5;
console.log(ints.length); // 2
console.log(ints[2]); // undefined
在這個(gè)示例中,盡管將數(shù)值索引2賦值為5浴井,但
ints
數(shù)組尺寸并未增長(zhǎng)晒骇,賦值被丟棄,length
屬性保持不變定型數(shù)組同樣會(huì)檢查數(shù)據(jù)類(lèi)型的合法性磺浙,0被用于代替所有非法值
let ints = new Int16Array(["hi"]);
console.log(ints.length); // 1
console.log(ints[0]); // 0
這段代碼嘗試向
Int16Array
數(shù)組中添加字符串值"hi"
洪囤,字符串在定型數(shù)組中屬于非法數(shù)據(jù)類(lèi)型,所以該值被轉(zhuǎn)換為0插入數(shù)組撕氧,數(shù)組的長(zhǎng)度仍然為1瘤缩,ints[0]
包含的值為0所有修改定型數(shù)組值的方法執(zhí)行時(shí)都會(huì)受到相同限制,例如伦泥,如果給
map()
方法傳入的函數(shù)返回非法值剥啤,則最終會(huì)用0來(lái)代替
mapped = ints.map(v => "hi");
console.log(mapped.length); // 2
console.log(mapped[0]); // 0
console.log(mapped[1]); // 0
console.log(mapped instanceof Int16Array); // true
console.log(mapped instanceof Array); // false
- 這里的字符串
"hi"
不是16位整數(shù)锦溪,所以在結(jié)果數(shù)組中會(huì)用0來(lái)替代它。由于有了這種錯(cuò)誤更正的特性府怯,故非法數(shù)據(jù)將不會(huì)在數(shù)組中出現(xiàn)刻诊,即使混入非法數(shù)據(jù)也不會(huì)拋出錯(cuò)誤
【缺失的方法】
盡管定型數(shù)組包含許多與普通數(shù)組相同的方法,但也缺失了幾個(gè)牺丙。以下方法在定型數(shù)組中不可使用
concat()
pop()
push()
shift()
splice()
unshift()
- 除
concat()
方法外则涯,這個(gè)列表中的方法都可以改變數(shù)組的尺寸,由于定型數(shù)組的尺寸不可更改冲簿,因而這些方法不適用于定型數(shù)組粟判。定型數(shù)組不支持concat()
方法是因?yàn)閮蓚€(gè)定型數(shù)組合并后的結(jié)果(尤其當(dāng)兩個(gè)數(shù)組分別處理不同數(shù)據(jù)類(lèi)型時(shí))會(huì)變得不確定,這直接違背了使用定型數(shù)組的初衷
【附加方法】
定型數(shù)組中還有兩個(gè)沒(méi)出現(xiàn)在普通數(shù)組中的方法
set()
和subarray()
峦剔。這兩個(gè)方法的功能相反档礁,set()
方法將其他數(shù)組復(fù)制到已有的定型數(shù)組,subarray()
提取已有定型數(shù)組的一部分作為一個(gè)新的定型數(shù)組
set()
方法接受兩個(gè)參數(shù):一個(gè)是數(shù)組(定型數(shù)組或普通數(shù)組都支持)吝沫;一個(gè)是可選的偏移量事秀,表示開(kāi)始插入數(shù)據(jù)的位置,如果什么都不傳野舶,默認(rèn)的偏移量為0易迹。合法數(shù)據(jù)從作為參數(shù)傳入的數(shù)組復(fù)制至目標(biāo)定型數(shù)組中
let ints = new Int16Array(4);
ints.set([25, 50]);
ints.set([75, 100], 2);
console.log(ints.toString()); // 25,50,75,100
這段代碼創(chuàng)建了一個(gè)含有4個(gè)元素的數(shù)組
Int16Array
,先調(diào)用set()
方法將兩個(gè)值分別復(fù)制到前兩個(gè)位置平道,再次調(diào)用set()
方法并傳入偏移量2睹欲,將另外兩個(gè)值復(fù)制到數(shù)組的后兩個(gè)位置subarray()
方法接受兩個(gè)參數(shù):一個(gè)是可選的開(kāi)始位置,一個(gè)是可選的結(jié)束位置(與slice()
方法的結(jié)束位置一樣一屋,不包含當(dāng)前位置的數(shù)據(jù))窘疮,最后返回一個(gè)新的定型數(shù)組。也可以省略這兩個(gè)參數(shù)來(lái)克隆一個(gè)新的定型數(shù)組
let ints = new Int16Array([25, 50, 75, 100]),
subints1 = ints.subarray(),
subints2 = ints.subarray(2),
subints3 = ints.subarray(1, 3);
console.log(subints1.toString()); // 25,50,75,100
console.log(subints2.toString()); // 75,100
console.log(subints3.toString()); // 50,75
- 以上示例中冀墨,分別通過(guò)原始數(shù)組
ints
創(chuàng)建了3個(gè)不同的定型數(shù)組闸衫。數(shù)組subints1
是通過(guò)克隆ints
得到的,故它們包含相同的信息诽嘉;數(shù)組subints2
從索引2開(kāi)始復(fù)制數(shù)據(jù)蔚出,所以只包含數(shù)組ints
的最后兩個(gè)元素(75和100);數(shù)組subints3
由于調(diào)用subarray()
方法時(shí)傳入了起始和結(jié)束索引的位置虫腋,故subints3
只包含數(shù)組ints
中間的兩個(gè)元素
其他章節(jié)
- ES6-數(shù)字?jǐn)U展
- ES6-字符串拓展
- ES6-模板字面量
- ES6-關(guān)于Unicode的相關(guān)擴(kuò)展
- ES6-正則表達(dá)式擴(kuò)展
- ES6-函數(shù)擴(kuò)展
- ES6-對(duì)象擴(kuò)展
- ES6-Symbol
- ES6-Set和Map集合
- ES6-數(shù)組擴(kuò)展
- ES6-定型數(shù)組
- ES6-塊級(jí)作用域
- ES6-解構(gòu)賦值
- ES6-類(lèi)
- ES6-代理(Proxy)和反射(Reflection)
- ES6-ES6中的模塊
- ES6-ES2017中的修飾器Decorator
- ES6-迭代器(Iterator)和生成器(Generator)
- ES6-Promise和異步編程
- ES6-ES2017中的async