ArrayBuffer
建構函式ArrayBuffer
方法ArrayBuffer.prototype
屬性TypedArray
方法TypedArray.prototype
屬性«ElementType»Array
建構函式«ElementType»Array
屬性«ElementType»Array.prototype
屬性DataView
建構函式DataView.prototype
屬性XMLHttpRequest
打字化陣列是 ECMAScript 6 處理二進位資料的 API。
程式碼範例
const
typedArray
=
new
Uint8Array
([
0
,
1
,
2
]);
console
.
log
(
typedArray
.
length
);
// 3
typedArray
[
0
]
=
5
;
const
normalArray
=
[...
typedArray
];
// [5,1,2]
// The elements are stored in typedArray.buffer.
// Get a different view on the same data:
const
dataView
=
new
DataView
(
typedArray
.
buffer
);
console
.
log
(
dataView
.
getUint8
(
0
));
// 5
ArrayBuffer
的實例儲存要處理的二進位資料。兩種「檢視」用於存取資料
Uint8Array
、Int16Array
、Float32Array
等)將 ArrayBuffer 解釋為單一類型元素的索引序列。DataView
的實例讓您存取資料為多種類型(Uint8
、Int16
、Float32
等)的元素,在 ArrayBuffer 內的任何位元組偏移量。下列瀏覽器 API 支援 Typed Arrays(詳細資訊請參閱專屬區段)
在網路上遇到的許多資料都是文字:JSON 檔案、HTML 檔案、CSS 檔案、JavaScript 程式碼等。對於處理此類資料,JavaScript 內建的字串資料類型運作良好。然而,直到幾年前,JavaScript 對於處理二進位資料的配備仍不齊全。2011 年 2 月 8 日,Typed Array 規格 1.0 標準化了處理二進位資料的設施。到目前為止,Typed Arrays 已受到各種引擎的良好支援。透過 ECMAScript 6,它們成為核心語言的一部分,並在過程中獲得許多先前僅供陣列使用的函式(map()
、filter()
等)。
Typed Arrays 的主要使用案例為
在 Typed Array API 中,有兩種物件會共同運作
ArrayBuffer
的執行個體會儲存二進位資料。Uint8Array
、Float64Array
等)的運作方式與一般陣列非常類似,但只允許其元素為單一類型,且沒有空洞。DataView
的執行個體讓您存取緩衝區中任何位元組偏移的資料,並將該資料解譯為數種類型之一(Uint8
、Float64
等)。這是分組陣列 API 結構的圖表(注意:所有分組陣列都有共同的超類別)
API 支援下列元素類型
元素類型 | 位元組 | 說明 | C 類型 |
---|---|---|---|
Int8 | 1 | 8 位元有號整數 | signed char |
Uint8 | 1 | 8 位元無號整數 | unsigned char |
Uint8C | 1 | 8 位元無號整數(壓縮轉換) | unsigned char |
Int16 | 2 | 16 位元有號整數 | short |
Uint16 | 2 | 16 位元無號整數 | unsigned short |
Int32 | 4 | 32 位元有號整數 | int |
Uint32 | 4 | 32 位元無號整數 | unsigned int |
Float32 | 4 | 32 位元浮點數 | float |
Float64 | 8 | 64 位元浮點數 | double |
元素類型 Uint8C
很特別:DataView
不支援它,它只存在於啟用 Uint8ClampedArray
。這個分組陣列由 canvas
元素使用(它取代了 CanvasPixelArray
)。Uint8C
和 Uint8
之間唯一的差異是溢位和下溢的處理方式(如下一節所述)。建議避免使用前者 – 引述 Brendan Eich
為了非常清楚(而且我從它誕生時就在場),
Uint8ClampedArray
完全 是歷史產物(HTML5 canvas 元素)。除非您真的在做 canvas 相關的事情,否則請避免使用它。
通常,當值超出元素類型的範圍時,會使用模數運算將其轉換為範圍內的數值。對於有號和無號整數,這表示
無號 8 位元整數的模數轉換
> const uint8 = new Uint8Array(1);
> uint8[0] = 255; uint8[0] // highest value within range
255
> uint8[0] = 256; uint8[0] // overflow
0
> uint8[0] = 0; uint8[0] // lowest value within range
0
> uint8[0] = -1; uint8[0] // underflow
255
有號 8 位元整數的模數轉換
> const int8 = new Int8Array(1);
> int8[0] = 127; int8[0] // highest value within range
127
> int8[0] = 128; int8[0] // overflow
-128
> int8[0] = -128; int8[0] // lowest value within range
-128
> int8[0] = -129; int8[0] // underflow
127
箝制轉換不同
> const uint8c = new Uint8ClampedArray(1);
> uint8c[0] = 255; uint8c[0] // highest value within range
255
> uint8c[0] = 256; uint8c[0] // overflow
255
> uint8c[0] = 0; uint8c[0] // lowest value within range
0
> uint8c[0] = -1; uint8c[0] // underflow
0
每當類型(例如 Uint16
)儲存為多個位元組時,位元序很重要
Uint16
值 0xABCD 儲存為兩個位元組,首先是 0xAB,然後是 0xCD。Uint16
值 0xABCD 儲存為兩個位元組,首先是 0xCD,然後是 0xAB。位元序傾向於每個 CPU 架構固定,並且在原生 API 中保持一致。類型化陣列用於與這些 API 通訊,這就是為什麼它們的位元序遵循平台的位元序並且無法更改的原因。
另一方面,協定和二進位檔案的位元序會有所不同,並且在各平台間固定。因此,我們必須能夠以任一種位元序存取資料。DataView 服務此用例,並讓您在取得或設定值時指定位元序。
您可以使用下列函數來判斷平台的位元序。
const
BIG_ENDIAN
=
Symbol
(
'BIG_ENDIAN'
);
const
LITTLE_ENDIAN
=
Symbol
(
'LITTLE_ENDIAN'
);
function
getPlatformEndianness
()
{
const
arr32
=
Uint32Array
.
of
(
0x12345678
);
const
arr8
=
new
Uint8Array
(
arr32
.
buffer
);
switch
((
arr8
[
0
]
*
0x1000000
)
+
(
arr8
[
1
]
*
0x10000
)
+
(
arr8
[
2
]
*
0x100
)
+
(
arr8
\
[
3
]))
{
case
0x12345678
:
return
BIG_ENDIAN
;
case
0x78563412
:
return
LITTLE_ENDIAN
;
default
:
throw
new
Error
(
'Unknown endianness'
);
}
}
還有一些平台會以與字元組內部位元組不同的位元序排列字元(成對的位元組)。這稱為混合位元序。如果您想支援這樣的平台,那麼很容易延伸先前的程式碼。
使用方括號運算子 [ ]
,您只能使用非負數索引(從 0 開始)。ArrayBuffer、類型化陣列和 DataView 的方法工作方式不同:每個索引都可以為負數。如果是這樣,它會從長度向後計算。換句話說,它會加到長度以產生一個正常的索引。因此,-1
表示最後一個元素,-2
表示倒數第二個,依此類推。一般陣列的方法工作方式相同。
> const ui8 = Uint8Array.of(0, 1, 2);
> ui8.slice(-1)
Uint8Array [ 2 ]
另一方面,偏移量必須是非負數。例如,如果您傳遞 -1
給
DataView
.
prototype
.
getInt8
(
byteOffset
)
那麼您會得到一個 RangeError
。
ArrayBuffers 儲存資料,檢視(類型化陣列和資料檢視)讓您可以讀取和變更它。為了建立資料檢視,您需要提供其建構函式一個 ArrayBuffer。類型化陣列建構函式可以選擇性地為您建立一個 ArrayBuffer。
ArrayBuffer
建構函式 建構函式的簽章是
ArrayBuffer
(
length
:
number
)
透過 new
呼叫這個建構函式會建立一個容量為 length
位元組的執行個體。這些位元組中的每個最初都是 0。
ArrayBuffer
方法 ArrayBuffer.isView(arg)
arg
是物件且為 ArrayBuffer 的檢視,則傳回 true
。只有類型化陣列和資料檢視具有必要的內部插槽 [[ViewedArrayBuffer]]
。這表示這個檢查大致等同於檢查 arg
是否為類型化陣列或 DataView
的執行個體。ArrayBuffer.prototype
屬性 取得 ArrayBuffer.prototype.byteLength
ArrayBuffer.prototype.slice(start, end)
start
且小於 end
。start
和 end
可以為負數(請參閱節「負數索引」)。各種類型的類型化陣列僅在其元素的類型方面有所不同
Int8Array
、Uint8Array
、Uint8ClampedArray
、Int16Array
、Uint16Array
、Int32Array
、Uint32Array
Float32Array
、Float64Array
類型化陣列很像一般陣列:它們有 length
,元素可透過括號運算子 [ ]
存取,而且它們具有所有標準陣列方法。它們與陣列的差異如下
arr.length
) 中的索引沒有關聯的元素),但類型化陣列不行。new Array(10)
會建立一個沒有任何元素的一般陣列(它只有空洞)。new Uint8Array(10)
會建立一個類型化陣列,其 10 個元素全部為 0。ta
的元素不會儲存在 ta
中,而是儲存在可透過 ta.buffer
存取的關聯 ArrayBuffer 中。類型化陣列實作一個其金鑰為 Symbol.iterator
的方法,因此可迭代(請參閱章節「可迭代物件和迭代器」以取得更多資訊)。這表示您可以在 ES6 中使用 for-of
迴圈和類似機制
const
ui8
=
Uint8Array
.
of
(
0
,
1
,
2
);
for
(
const
byte
of
ui8
)
{
console
.
log
(
byte
);
}
// Output:
// 0
// 1
// 2
ArrayBuffer 和 DataView 不可迭代。
若要將一般陣列轉換為類型化陣列,請將其設為類型化陣列建構函式的參數。例如
> const tarr = new Uint8Array([0,1,2]);
將類型化陣列轉換為陣列的傳統方式是在其上呼叫 Array.prototype.slice
。此技巧適用於所有類陣列物件(例如 arguments
),而且類型化陣列是類陣列。
> Array.prototype.slice.call(tarr)
[ 0, 1, 2 ]
在 ES6 中,您可以使用展開運算子 (...
),因為類型化陣列可迭代
> [...tarr]
[ 0, 1, 2 ]
另一種 ES6 替代方案是 Array.from()
,它可與可迭代物件或類陣列物件搭配使用
> Array.from(tarr)
[ 0, 1, 2 ]
有些方法會建立與 this
類似的新的執行個體。Species 模式讓您可以設定應使用哪個建構函式來執行此動作。例如,如果您建立 Array
的子類別 MyArray
,則預設值是 map()
會建立 MyArray
的執行個體。如果您想要建立 Array
的執行個體,您可以使用 Species 模式來達成此目的。詳細資訊說明於章節「Species 模式」中的類別章節。
ArrayBuffer 在以下位置使用 Species 模式
ArrayBuffer.prototype.slice()
類型化陣列在以下位置使用 Species 模式
TypedArray<T>.prototype.filter()
TypedArray<T>.prototype.map()
TypedArray<T>.prototype.slice()
TypedArray<T>.prototype.subarray()
DataViews 不使用 species 模式。
正如您在本章開頭的圖表中所見,所有 Typed Array 類別(Uint8Array
等)都有共同的超類別。我稱呼該超類別為 TypedArray
,但它無法直接從 JavaScript 存取(ES6 規格稱之為內在物件 %TypedArray%
)。TypedArray.prototype
包含 Typed Array 的所有方法。
TypedArray
方法 靜態 TypedArray
方法皆由其子類別繼承(Uint8Array
等)。
TypedArray.of()
此方法具有簽章
TypedArray
.
of
(...
items
)
它會建立一個新的 Typed Array,為 this
的執行個體(呼叫 of()
的類別)。該執行個體的元素為 of()
的參數。
您可以將 of()
視為 Typed Array 的自訂文字
> Float32Array.of(0.151, -8, 3.7)
Float32Array [ 0.151, -8, 3.7 ]
TypedArray.from()
此方法具有簽章
TypedArray
<
U
>
.
from
(
source
:
Iterable
<
T
>
,
mapfn
?
:
T
=>
U
,
thisArg
?
)
它會將可迭代的 source
轉換為 this
的執行個體(Typed Array)。
例如,一般陣列可迭代,且可以使用此方法轉換
> Uint16Array.from([0, 1, 2])
Uint16Array [ 0, 1, 2 ]
Typed Array 也可迭代
> const ui16 = Uint16Array.from(Uint8Array.of(0, 1, 2));
> ui16 instanceof Uint16Array
true
選用的 mapfn
讓您可以在 source
的元素成為結果的元素之前轉換它們。為何要一次執行兩個步驟對應和轉換?與透過 source.map()
分別執行第一步相比,有兩個優點
為了說明第二個優點,我們使用 map()
將 Typed Array 的元素加倍
> Int8Array.of(127, 126, 125).map(x => 2 * x)
Int8Array [ -2, -4, -6 ]
正如您所見,值會溢位並轉換為 Int8
值範圍。如果透過 from()
對應,您可以選擇結果的類型,以避免值溢位
> Int16Array.from(Int8Array.of(127, 126, 125), x => 2 * x)
Int16Array [ 254, 252, 250 ]
根據 Allen Wirfs-Brock的說法,在 Typed Array 之間對應是 from()
的 mapfn
參數的動機。
TypedArray.prototype
屬性 Typed Array 方法所接受的索引可以是負值(它們像傳統的 Array 方法那樣運作)。偏移量必須是非負值。有關詳細資訊,請參閱「負索引」一節。
下列屬性特定於 Typed Array,一般 Array 沒有這些屬性
取得 TypedArray<T>.prototype.buffer : ArrayBuffer
取得 TypedArray<T>.prototype.byteLength : number
取得 TypedArray<T>.prototype.byteOffset : number
TypedArray<T>.prototype.set(arrayOrTypedArray, offset=0) : void
arrayOrTypedArray
的所有元素複製到此 Typed Array。arrayOrTypedArray
的索引 0 處的元素寫入此 Typed Array 的索引 offset
處(依此類推)。
arrayOrTypedArray
是個一般 Array,其元素會轉換為數字,然後再轉換為此 Typed Array 的元素類型 T
。arrayOrTypedArray
是個 Typed Array,則其每個元素會直接轉換為此 Typed Array 的適當類型。如果兩個 Typed Array 有相同的元素類型,則會使用較快的位元組複製。TypedArray<T>.prototype.subarray(begin=0, end=this.length) : TypedArray<T>
begin
為非負值,則結果 Typed Array 的第一個元素為 this[begin]
,第二個為 this[begin+1]
(依此類推)。如果 begin
為負值,則會適當轉換。下列方法基本上與一般 Array 的方法相同
TypedArray<T>.prototype.copyWithin(target : number, start : number, end = this.length) : This
start
(包含)和 end
(不包含)之間的元素複製到從 target
開始的索引。如果範圍重疊,且前一個範圍在先,則會以反向順序複製元素,以避免在複製前覆寫來源元素。TypedArray<T>.prototype.entries() : Iterable<[number,T]>
TypedArray<T>.prototype.every(callbackfn, thisArg?)
TypedArray<T>.prototype.fill(value, start=0, end=this.length) : void
TypedArray<T>.prototype.filter(callbackfn, thisArg?) : TypedArray<T>
TypedArray<T>.prototype.find(predicate : T => boolean, thisArg?) : T
TypedArray<T>.prototype.findIndex(predicate : T => boolean, thisArg?) : number
TypedArray<T>.prototype.forEach(callbackfn, thisArg?) : void
TypedArray<T>.prototype.indexOf(searchElement, fromIndex=0) : number
TypedArray<T>.prototype.join(separator : string = ',') : string
TypedArray<T>.prototype.keys() : Iterable<number>
TypedArray<T>.prototype.lastIndexOf(searchElement, fromIndex?) : number
get TypedArray<T>.prototype.length : number
TypedArray<T>.prototype.map(callbackfn, thisArg?) : TypedArray<T>
TypedArray<T>.prototype.reduce(callbackfn : (previousValue : any, currentElement : T, currentIndex : number, array : TypedArray<T>) => any, initialValue?) : any
TypedArray<T>.prototype.reduceRight(callbackfn : (previousValue : any, currentElement : T, currentIndex : number, array : TypedArray<T>) => any, initialValue?) : any
TypedArray<T>.prototype.reverse() : This
this
。TypedArray<T>.prototype.slice(start=0, end=this.length) : TypedArray<T>
start
(包含)和 end
(不包含)之間的此 Typed Array 元素。TypedArray<T>.prototype.some(callbackfn, thisArg?)
callbackfn
對此 Typed Array 的至少一個元素傳回 true
,則傳回 true
。否則,傳回 false
。some()
會在 callbackfn
第一次傳回 true
時停止處理。TypedArray<T>.prototype.sort(comparefn? : (number, number) => number)
comparefn
指定的方式,對此 Typed Array 進行排序。如果未指定 comparefn
,則會透過比較小於運算子 (<
) 來遞增排序。TypedArray<T>.prototype.toLocaleString(reserved1?, reserved2?)
TypedArray<T>.prototype.toString()
TypedArray<T>.prototype.values() : Iterable<T>
由於陣列可以使用所有這些方法,因此你可以參閱以下兩個來源,以進一步了解它們的工作方式
copyWithin
、entries
、fill
、find
、findIndex
、keys
、values
。請注意,雖然一般陣列方法是泛型的(任何類陣列的 this
都可以),但本節列出的方法並非如此(this
必須是 Typed Array)。
«ElementType»Array
建構函式 每個 Typed Array 建構函式都有遵循 «ElementType»Array
樣式的名稱,其中 «ElementType»
是開頭表格中的元素類型之一。這表示 Typed Array 有 9 個建構函式:Int8Array
、Uint8Array
、Uint8ClampedArray
(元素類型 Uint8C
)、Int16Array
、Uint16Array
、Int32Array
、Uint32Array
、Float32Array
、Float64Array
。
每個建構函式有五個重載版本 – 它的行為會根據接收到的引數數量及其類型而有所不同
«ElementType»Array(buffer, byteOffset=0, length?)
buffer
。它會從指定的 byteOffset
開始存取緩衝區,並具有指定的 length
。請注意,length
計算 Typed Array 的元素(每個元素有 1 到 4 個位元組),而不是位元組。«ElementType»Array(length)
length
和適當緩衝區(其位元組大小為 length * «ElementType»Array.BYTES_PER_ELEMENT
)的 Typed Array。«ElementType»Array()
«ElementType»Array(typedArray)
typedArray
相同。過大或過小的值會適當地轉換。«ElementType»Array(arrayLikeObject)
arrayLikeObject
視為一個 Array,並建立一個新的 TypedArray,其長度和元素與之相同。過大或過小的值會適當地轉換。以下程式碼顯示了建立相同 Typed Array 的三種不同方式
const
tarr1
=
new
Uint8Array
([
1
,
2
,
3
]);
const
tarr2
=
Uint8Array
.
of
(
1
,
2
,
3
);
const
tarr3
=
new
Uint8Array
(
3
);
tarr3
[
0
]
=
0
;
tarr3
[
1
]
=
1
;
tarr3
[
2
]
=
2
;
«ElementType»Array
屬性 «ElementType»Array.BYTES_PER_ELEMENT
> Uint8Array.BYTES_PER_ELEMENT
1
> Int16Array.BYTES_PER_ELEMENT
2
> Float64Array.BYTES_PER_ELEMENT
8
«ElementType»Array.prototype
屬性 «ElementType»Array.prototype.BYTES_PER_ELEMENT
«ElementType»Array.BYTES_PER_ELEMENT
相同。Typed Arrays 沒有像一般 Arrays 的 concat()
方法。解決方法是使用
typedArray
.
set
(
arrayOrTypedArray
,
offset
=
0
)
此方法會將現有的 Typed Array (或一般 Array) 複製到 typedArray
中的索引 offset
。然後你只需要確保 typedArray
足夠大,可以容納所有你想要串接的 (Typed) Arrays
function
concatenate
(
resultConstructor
,
...
arrays
)
{
let
totalLength
=
0
;
for
(
const
arr
of
arrays
)
{
totalLength
+=
arr
.
length
;
}
const
result
=
new
resultConstructor
(
totalLength
);
let
offset
=
0
;
for
(
const
arr
of
arrays
)
{
result
.
set
(
arr
,
offset
);
offset
+=
arr
.
length
;
}
return
result
;
}
console
.
log
(
concatenate
(
Uint8Array
,
Uint8Array
.
of
(
1
,
2
),
Uint8Array
.
of
(
3
,
4
)));
// Uint8Array [1, 2, 3, 4]
DataView
建構函式 DataView(buffer, byteOffset=0, byteLength=buffer.byteLength-byteOffset)
buffer
中。預設情況下,新的 DataView 可以存取所有 buffer
,後兩個參數允許你變更它。DataView.prototype
屬性 取得 DataView.prototype.buffer
取得 DataView.prototype.byteLength
取得 DataView.prototype.byteOffset
DataView.prototype.get«ElementType»(byteOffset, littleEndian=false)
«ElementType»
可以是:Float32
、Float64
、Int8
、Int16
、Int32
、Uint8
、Uint16
、Uint32
DataView.prototype.set«ElementType»(byteOffset, value, littleEndian=false)
value
寫入此 DataView 的緩衝區。
«ElementType»
可以是:Float32
、Float64
、Int8
、Int16
、Int32
、Uint8
、Uint16
、Uint32
Typed Array 已經存在一段時間了,因此有許多瀏覽器 API 支援它們。
檔案 API 讓您可以存取本機檔案。以下程式碼示範如何取得已提交本機檔案的位元組,並儲存在 ArrayBuffer 中。
const
fileInput
=
document
.
getElementById
(
'fileInput'
);
const
file
=
fileInput
.
files
[
0
];
const
reader
=
new
FileReader
();
reader
.
readAsArrayBuffer
(
file
);
reader
.
onload
=
function
()
{
const
arrayBuffer
=
reader
.
result
;
···
};
XMLHttpRequest
在較新的 XMLHttpRequest
API 版本中,您可以讓結果傳遞到 ArrayBuffer
const
xhr
=
new
XMLHttpRequest
();
xhr
.
open
(
'GET'
,
someUrl
);
xhr
.
responseType
=
'arraybuffer'
;
xhr
.
onload
=
function
()
{
const
arrayBuffer
=
xhr
.
response
;
···
};
xhr
.
send
();
與 XMLHttpRequest
類似,Fetch API 讓您可以要求資源。但它是基於 Promise,這讓它更方便使用。以下程式碼示範如何將 url
指向的內容下載為 ArrayBuffer
fetch
(
url
)
.
then
(
request
=>
request
.
arrayBuffer
())
.
then
(
arrayBuffer
=>
···
);
canvas
元素提供具解析度依賴性位圖畫布的指令碼,可立即用於繪製圖表、遊戲圖形、藝術或其他視覺影像。
canvas
的 2D Context 讓您可以將位圖資料擷取為 Uint8ClampedArray
的執行個體
const
canvas
=
document
.
getElementById
(
'my_canvas'
);
const
context
=
canvas
.
getContext
(
'2d'
);
const
imageData
=
context
.
getImageData
(
0
,
0
,
canvas
.
width
,
canvas
.
height
);
const
uint8ClampedArray
=
imageData
.
data
;
WebSockets 讓您可以透過 ArrayBuffers 傳送和接收二進位資料
const
socket
=
new
WebSocket
(
'ws://127.0.0.1:8081'
);
socket
.
binaryType
=
'arraybuffer'
;
// Wait until socket is open
socket
.
addEventListener
(
'open'
,
function
(
event
)
{
// Send binary data
const
typedArray
=
new
Uint8Array
(
4
);
socket
.
send
(
typedArray
.
buffer
);
});
// Receive binary data
socket
.
addEventListener
(
'message'
,
function
(
event
)
{
const
arrayBuffer
=
event
.
data
;
···
});
<audio>
和 <video>
。媒體來源擴充功能 API 讓您可以建立串流,以透過這些元素播放。您可以透過 ArrayBuffers、Typed Arrays 或 DataViews 將二進位資料新增至這些串流。postMessage()
將資料傳送至 Worker,訊息(將會複製)或可傳輸的物件可以包含 ArrayBuffers。postMessage()
方法。此範例是一個網頁,讓你可以上傳 JPEG 檔案,並解析其結構以判斷影像的高度和寬度,以及更多資訊。
JPEG 檔案是一連串的區段(類型化資料)。每個區段都從以下四個位元組開始
JPEG 檔案在所有平台上都是大端序。因此,此範例說明了在使用 DataViews 時,我們能夠指定端序的重要性。
以下函式 processArrayBuffer()
是實際程式碼的縮寫版本;我已移除一些錯誤檢查以減少雜訊。processArrayBuffer()
會接收一個包含已提交 JPEG 檔案內容的 ArrayBuffer,並反覆處理其區段。
// JPEG is big endian
var
IS_LITTLE_ENDIAN
=
false
;
function
processArrayBuffer
(
arrayBuffer
)
{
try
{
var
dv
=
new
DataView
(
arrayBuffer
);
···
var
ptr
=
2
;
while
(
true
)
{
···
var
lastPtr
=
ptr
;
enforceValue
(
0xFF
,
dv
.
getUint8
(
ptr
),
'Not a marker'
);
ptr
++
;
var
marker
=
dv
.
getUint8
(
ptr
);
ptr
++
;
var
len
=
dv
.
getUint16
(
ptr
,
IS_LITTLE_ENDIAN
);
ptr
+=
len
;
logInfo
(
'Marker: '
+
hex
(
marker
)
+
' ('
+
len
+
' byte(s))'
);
···
// Did we find what we were looking for?
if
(
marker
===
0xC0
)
{
// SOF0
logInfo
(
decodeSOF0
(
dv
,
lastPtr
));
break
;
}
}
}
catch
(
e
)
{
logError
(
e
.
message
);
}
}
此程式碼使用以下輔助函式(未在此處顯示)
enforceValue()
如果預期值(第一個參數)與實際值(第二個參數)不符,就會擲回錯誤。logInfo()
和 logError()
會在頁面上顯示訊息。hex()
會將數字轉換成包含兩個十六進位數字的字串。decodeSOF0()
會解析區段 SOF0
function
decodeSOF0
(
dv
,
start
)
{
// Example (16x16):
// FF C0 00 11 08 00 10 00 10 03 01 22 00 02 11 01 03 11 01
var
data
=
{};
start
+=
4
;
// skip marker 0xFFC0 and segment length 0x0011
var
data
=
{
bitsPerColorComponent
:
dv
.
getUint8
(
start
),
// usually 0x08
imageHeight
:
dv
.
getUint16
(
start
+
1
,
IS_LITTLE_ENDIAN
),
imageWidth
:
dv
.
getUint16
(
start
+
3
,
IS_LITTLE_ENDIAN
),
numberOfColorComponents
:
dv
.
getUint8
(
start
+
5
),
};
return
JSON
.
stringify
(
data
,
null
,
4
);
}
有關 JPEG 檔案結構的更多資訊
大部分的 Typed Array API 已由所有現代 JavaScript 引擎實作,但有幾個功能是 ECMAScript 6 的新功能
TypedArray<T>.from()
、TypedArray<T>.of()
TypedArray<T>.prototype.map()
等TypedArray<T>
是所有 Typed Array 類別的超類別可能需要一段時間才能在各處使用這些功能。與往常一樣,kangax 的「ES6 相容性表」說明了現狀。