ES6(十一):定型數(shù)組

前面的話


??定型數(shù)組是一種用于處理數(shù)值類(lèi)型(正如其名,不是所有類(lèi)型)數(shù)據(jù)的專(zhuān)用數(shù)組准浴,最早是在WebGL中使用的西傀,WebGLOpenGL 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è)視圖的byteOffsetbyteLength屬性又互不相同,這兩個(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ù)的方法翁涤。這些方法名都以setget打頭,緊跟著的是每一種數(shù)據(jù)類(lèi)型的縮寫(xiě)。例如迷雪,以下這個(gè)列表是用于讀取和寫(xiě)入int8unit8類(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ù)

以下示例分別展示了setget方法的實(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ù)。Uint8ClampedArrayuint8Array大致相同网缝,唯一的區(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)用DataViewsetget方法時(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í)例,view1view2有相同的buffer墩划、byteOffsetbyteLength屬性春塌,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)建Int16ArrayFloat32Array,通過(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é)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末骄酗,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子悦冀,更是在濱河造成了極大的恐慌趋翻,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,858評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件盒蟆,死亡現(xiàn)場(chǎng)離奇詭異踏烙,居然都是意外死亡师骗,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)讨惩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)丧凤,“玉大人,你說(shuō)我怎么就攤上這事步脓。” “怎么了浩螺?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,282評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵靴患,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我要出,道長(zhǎng)鸳君,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,842評(píng)論 1 295
  • 正文 為了忘掉前任患蹂,我火速辦了婚禮或颊,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘传于。我一直安慰自己囱挑,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布沼溜。 她就那樣靜靜地躺著平挑,像睡著了一般。 火紅的嫁衣襯著肌膚如雪系草。 梳的紋絲不亂的頭發(fā)上通熄,一...
    開(kāi)封第一講書(shū)人閱讀 51,679評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音找都,去河邊找鬼唇辨。 笑死,一個(gè)胖子當(dāng)著我的面吹牛能耻,可吹牛的內(nèi)容都是我干的赏枚。 我是一名探鬼主播,決...
    沈念sama閱讀 40,406評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼晓猛,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼嗡贺!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起鞍帝,我...
    開(kāi)封第一講書(shū)人閱讀 39,311評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤诫睬,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后帕涌,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體摄凡,經(jīng)...
    沈念sama閱讀 45,767評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡续徽,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了亲澡。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片钦扭。...
    茶點(diǎn)故事閱讀 40,090評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖床绪,靈堂內(nèi)的尸體忽然破棺而出客情,到底是詐尸還是另有隱情,我是刑警寧澤癞己,帶...
    沈念sama閱讀 35,785評(píng)論 5 346
  • 正文 年R本政府宣布膀斋,位于F島的核電站,受9級(jí)特大地震影響痹雅,放射性物質(zhì)發(fā)生泄漏仰担。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評(píng)論 3 331
  • 文/蒙蒙 一绩社、第九天 我趴在偏房一處隱蔽的房頂上張望摔蓝。 院中可真熱鬧,春花似錦愉耙、人聲如沸贮尉。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,988評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)绘盟。三九已至,卻和暖如春悯仙,著一層夾襖步出監(jiān)牢的瞬間龄毡,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,101評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工锡垄, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留沦零,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,298評(píng)論 3 372
  • 正文 我出身青樓货岭,卻偏偏與公主長(zhǎng)得像路操,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子千贯,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 數(shù)組 es6加入了一些數(shù)組的新功能屯仗,以及改進(jìn)了舊功能 保證永遠(yuǎn)傳的是數(shù)組的元素 將類(lèi)對(duì)象轉(zhuǎn)換成數(shù)組的方式 映射轉(zhuǎn)換...
    aymfx閱讀 526評(píng)論 0 0
  • es6針對(duì)Array進(jìn)行了功能上的改進(jìn)。 我們知道創(chuàng)建一個(gè)數(shù)組有兩種方式搔谴,一個(gè)是構(gòu)造函數(shù)方式魁袜,另外一個(gè)就是字面量方...
    xiaohesong閱讀 789評(píng)論 0 0
  • 原創(chuàng)文章&經(jīng)驗(yàn)總結(jié)&從校招到A廠一路陽(yáng)光一路滄桑 詳情請(qǐng)戳www.codercc.com 主要知識(shí)點(diǎn):創(chuàng)建數(shù)組、數(shù)...
    你聽(tīng)___閱讀 1,038評(píng)論 0 2
  • 二進(jìn)制數(shù)組(ArrayBuffer對(duì)象、TypedArray視圖和DataView視圖)是JavaScript操作...
    呼呼哥閱讀 21,308評(píng)論 2 12
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒(méi)有地址/指針的概念1.2> 泛型1.3> 類(lèi)型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,103評(píng)論 1 32