## 29.類型化數組:處理二進制數據(高級)
> 原文: [http://exploringjs.com/impatient-js/ch_typed-arrays.html](http://exploringjs.com/impatient-js/ch_typed-arrays.html)
>
> 貢獻者:[steve000](https://github.com/steve000)
### 29.1。 API 的基礎知識
Web 上的大量數據是:文本、JSON 文件、HTML 文件、CSS 文件、JavaScript 代碼等。JavaScript 通過其內置字符串很好地處理這些數據。
但是,在 2011 年之前,它沒有很好地處理二進制數據。 [2011 年 2 月 8 日推出了 Typed Array Specification 1.0](https://www.khronos.org/registry/typedarray/specs/1.0/) ,并提供了處理二進制數據的工具。使用 ECMAScript 6,將類型數組添加到核心語言中,并獲得以前僅適用于普通數組(`.map()`,`.filter()`等)的方法。
#### 29.1.1。 Typed Arrays 的用例
Typed Arrays 的主要用例是:
* 處理二進制數據:處理 HTML Canvas 元素中的圖像數據,解析二進制文件,處理二進制網絡協議等。
* 與本機 API 交互:本機 API 通常以二進制格式接收和返回數據,您無法在 ES6 之前的 JavaScript 中存儲或操作。這意味著,無論何時與這種 API 進行通信,每次調用時都必須將數據從 JavaScript 轉換為二進制并返回。 Typed Arrays 消除了這個瓶頸。與本機 API 通信的一個示例是 WebGL,最初為其創建了 Typed Arrays。文章[“類型數組:瀏覽器中的二進制數據”](http://www.html5rocks.com/en/tutorials/webgl/typed_arrays/#toc-history)(由 Ilmari Heikkinen 為 HTML5 Rocks 提供)[“類型數組的歷史”](http://www.html5rocks.com/en/tutorials/webgl/typed_arrays/#toc-history)部分提供了更多信息。
#### 29.1.2。支持 Typed Arrays 的瀏覽器 API
以下瀏覽器 API 支持 Typed Arrays:
* [文件 API](http://www.w3.org/TR/FileAPI/)
* [`XMLHttpRequest`](http://www.w3.org/TR/XMLHttpRequest/)
* [Fetch API](https://fetch.spec.whatwg.org/)
* [畫布](http://www.w3.org/TR/2dcontext/)
* [WebSockets](http://www.w3.org/TR/websockets/)
* [WebGL](https://www.khronos.org/registry/webgl/)
* [網絡音頻 API](http://www.w3.org/TR/webaudio/)
* (和更多)
#### 29.1.3。核心類:`ArrayBuffer`,類型數組,`DataView`
Typed Array API 將二進制數據存儲在`ArrayBuffer`的實例中:
```js
const buf = new ArrayBuffer(4); // length in bytes
// buf is initialized with zeros
```
ArrayBuffer 本身是不透明的。如果要訪問其數據,則必須將其包裝在另一個對象中 - _ 視圖對象 _。有兩種視圖對象可供選擇:
* 類型化數組:允許您將數據作為所有具有相同類型的索引元素序列進行訪問。例子包括:
* `Uint8Array`:元素是無符號 8 位整數。 _ 無符號 _ 表示它們的范圍從零開始。
* `Int16Array`:元素是帶符號的 16 位整數。 _ 簽名 _ 意味著他們有一個標志,可以是負數,零或正數。
* `Float32Array`:元素是 32 位浮點數。
* DataViews:允許您將數據解釋為可以在任何字節偏移處讀取和寫入的各種類型(`Uint8`,`Int16`,`Float32`等)。
圖 [19](#fig:typed_arrays_class_diagram) 顯示了 API 的類圖。

Figure 19: The classes of the Typed Array API.
#### 29.1.4。使用 Typed Arrays
類型數組的使用方式與普通數組非常相似,但有一些顯著差異:
* Typed Arrays 將其數據存儲在 ArrayBuffers 中。
* 所有元素都用零初始化。
* 所有元素都具有相同的類型。將值寫入類型化數組會將它們強制轉換為該類型。讀取值會產生正常數字。
* 創建類型化數組后,其長度永遠不會改變。
* Typed Arrays 不能有洞。
這是使用類型化數組的示例:
```js
const typedArray = new Uint8Array(2); // 2 elements
assert.equal(typedArray.length, 2);
// The wrapped ArrayBuffer
assert.deepEqual(
typedArray.buffer, new ArrayBuffer(2)); // 2 bytes
// Getting and setting elements:
assert.equal(typedArray[1], 0); // initialized with 0
typedArray[1] = 72;
assert.equal(typedArray[1], 72);
```
其他創建類型數組的方法:
```js
const ta1 = new Uint8Array([5, 6]);
const ta2 = Uint8Array.of(5, 6);
assert.deepEqual(ta1, ta2);
```
#### 29.1.5。使用 DataViews
這就是 DataViews 的使用方式:
```js
const dataView = new DataView(new ArrayBuffer(4));
assert.equal(dataView.getUint16(0), 0);
assert.equal(dataView.getUint8(0), 0);
dataView.setUint8(0, 5);
```
### 29.2。 Typed Array API 的基礎
#### 29.2.1。元素類型
API 支持以下元素類型:
| 元素類型 | 字節 | 描述 | C 型 |
| --- | --- | --- | --- |
| INT8 | 1 | 8 位有符號整數 | 簽名的 char |
| UINT8 | 1 | 8 位無符號整數 | 無符號的字符 |
| Uint8C | 1 | 8 位無符號整數(鉗位轉換) | 無符號的字符 |
| INT16 | 2 | 16 位有符號整數 | 短 |
| UINT16 | 2 | 16 位無符號整數 | 未簽約的短片 |
| INT32 | 4 | 32 位有符號整數 | INT |
| UINT32 | 4 | 32 位無符號整數 | unsigned int |
| FLOAT32 | 4 | 32 位浮點 | 浮動 |
| Float64 | 8 | 64 位浮點 | 雙 |
元素類型`Uint8C`是特殊的:`DataView`不支持它,僅存在以啟用`Uint8ClampedArray`。這個類型數組由`canvas`元素使用(它替換`CanvasPixelArray`)。 `Uint8C`和`Uint8`之間的唯一區別是溢出和下溢的處理方式(如下一節所述)。建議避免前者 - [引用 Brendan Eich](https://mail.mozilla.org/pipermail/es-discuss/2015-August/043902.html) :
> 只是為了超級清晰(我出生時就在身邊),`Uint8ClampedArray`完全是一個歷史神器(HTML5 畫布元素)。除非你真的在做帆布的事情,否則要避免。
#### 29.2.2。處理溢出和下溢
通常,當值超出元素類型的范圍時,使用模運算將其轉換為范圍內的值。對于有符號和無符號整數,這意味著:
* 最高值加 1 將轉換為最低值(0 表示無符號整數)。
* 最低值減 1 將轉換為最高值。
以下功能有助于說明轉換的工作原理:
```js
function setAndGet(typedArray, value) {
typedArray[0] = value;
return typedArray[0];
}
```
無符號 8 位整數的模數轉換:
```js
const uint8 = new Uint8Array(1);
// Highest value of range
assert.equal(setAndGet(uint8, 255), 255);
// Overflow
assert.equal(setAndGet(uint8, 256), 0);
// Lowest value of range
assert.equal(setAndGet(uint8, 0), 0);
// Underflow
assert.equal(setAndGet(uint8, -1), 255);
```
有符號 8 位整數的模數轉換:
```js
const int8 = new Int8Array(1);
// Highest value of range
assert.equal(setAndGet(int8, 127), 127);
// Overflow
assert.equal(setAndGet(int8, 128), -128);
// Lowest value of range
assert.equal(setAndGet(int8, -128), -128);
// Underflow
assert.equal(setAndGet(int8, -129), 127);
```
夾緊轉換是不同的:
* 所有下溢值都將轉換為最低值。
* 所有溢出值都將轉換為最高值。
```js
const uint8c = new Uint8ClampedArray(1);
// Highest value of range
assert.equal(setAndGet(uint8c, 255), 255);
// Overflow
assert.equal(setAndGet(uint8c, 256), 255);
// Lowest value of range
assert.equal(setAndGet(uint8c, 0), 0);
// Underflow
assert.equal(setAndGet(uint8c, -1), 0);
```
#### 29.2.3。字節序
每當一個類型(例如`Uint16`)被存儲為多個字節的序列時, _endianness_ 很重要:
* Big endian:最重要的字節首先出現。例如,`Uint16`值 0x4321 存儲為兩個字節 - 首先是 0x43,然后是 0x21。
* 小端:最不重要的字節首先出現。例如,`Uint16`值 0x4321 存儲為兩個字節 - 首先是 0x21,然后是 0x43。
Endianness 往往是針對每個 CPU 架構固定的,并且在本機 API 之間保持一致。類型化數組用于與這些 API 通信,這就是為什么它們的字節順序遵循平臺的字節順序而無法更改。
另一方面,協議和二進制文件的字節順序各不相同,并且在不同平臺上是固定的。因此,我們必須能夠以任何字節順序訪問數據。 DataViews 提供此用例,并允許您在獲取或設置值時指定字節序。
[引用關于 Endianness 的維基百科](https://en.wikipedia.org/wiki/Endianness):
* Big-endian 表示是數據網絡中最常見的慣例; Internet 協議套件協議中的字段,如 IPv4,IPv6,TCP 和 UDP,以 big-endian 順序傳輸。因此,big-endian 字節順序也稱為網絡字節順序。
* 小端存儲器在微處理器中很受歡迎,部分原因是英特爾公司對微處理器設計產生了重大的歷史影響。
您可以使用以下函數來確定平臺的字節順序。
```js
const BIG_ENDIAN = Symbol('BIG_ENDIAN');
const LITTLE_ENDIAN = Symbol('LITTLE_ENDIAN');
function getPlatformEndianness() {
const arr32 = Uint32Array.of(0x87654321);
const arr8 = new Uint8Array(arr32.buffer);
if (compare(arr8, [0x87, 0x65, 0x43, 0x21])) {
return BIG_ENDIAN;
} else if (compare(arr8, [0x21, 0x43, 0x65, 0x87])) {
return LITTLE_ENDIAN;
} else {
throw new Error('Unknown endianness');
}
}
function compare(arr1, arr2) {
if (arr1.length !== arr2.length) {
return false;
}
for (let i=0; i<arr1.length; i++) {
if (arr1[i] !== arr2[i]) {
return false;
}
}
return true;
}
```
其他排序也是可能的。這些通常被稱為 _ 中端 _ 或 _ 混合端 _。
#### 29.2.4。指數和抵消
對于 Typed Arrays,我們區分:
* 括號運算符的指數`[ ]`:您只能使用非負指數(從 0 開始)。
* ArrayBuffers,Typed Arrays 和 DataViews 方法的索引:每個索引都可以是負數。如果是,則將其添加到實體的長度,以生成實際索引。因此,`-1`指的是最后一個元素,`-2`指向倒數第二個等。正常數組的方法以相同的方式工作。
```js
const ui8 = Uint8Array.of(0, 1, 2);
assert.deepEqual(ui8.slice(-1), Uint8Array.of(2));
```
* 傳遞給 Typed Arrays 和 DataViews 方法的偏移量:必須是非負數。例如:
```js
const dataView = new DataView(new ArrayBuffer(4));
assert.throws(
() => dataView.getUint8(-1),
{
name: 'RangeError',
message: 'Offset is outside the bounds of the DataView',
});
```
### 29.3。 ArrayBuffers
ArrayBuffers 存儲二進制數據,可通過 Typed Arrays 和 DataViews 訪問。
#### 29.3.1。 `new ArrayBuffer()`
構造函數的類型簽名是:
```js
new ArrayBuffer(length: number)
```
通過`new`調用此構造函數會創建一個容量為`length`字節的實例。每個字節最初為 0。
您無法更改 ArrayBuffer 的長度,您只能創建一個具有不同長度的新長度。
#### 29.3.2。 `ArrayBuffer`的靜態方法
* `ArrayBuffer.isView(arg: any)`
如果`arg`是對象,則返回`true`,返回 ArrayBuffer(Typed Array 或 DataView)的視圖。
#### 29.3.3。 `ArrayBuffer.prototype`的屬性
* `get .byteLength(): number`
以字節為單位返回此 ArrayBuffer 的容量。
* `.slice(startIndex: number, endIndex=this.byteLength)`
創建一個新的 ArrayBuffer,其中包含此 ArrayBuffer 的字節,其索引大于或等于`startIndex`且小于`endIndex`。 `start`和`endIndex`可以是負數(參見[“指數和偏移”](ch_typed-arrays.html#typed-arrays-indices-offsets)部分)。
### 29.4。鍵入的數組
各種類型的數組只是不同的 w.r.t.他們的元素類型:
* 元素為整數的類型化數組:`Int8Array`,`Uint8Array`,`Uint8ClampedArray`,`Int16Array`,`Uint16Array`,`Int32Array`,`Uint32Array`
* 元素為浮點數的類型數組:`Float32Array`,`Float64Array`
#### 29.4.1。鍵入數組與普通數組
類型數組與普通數組非常相似:它們有`.length`,元素可以通過括號運算符`[ ]`訪問,并且它們具有大多數標準數組方法。它們在以下方面與普通數組不同:
* Typed Arrays 有緩沖區。類型數組`ta`的元素不存儲在`ta`中,它們存儲在可通過`ta.buffer`訪問的關聯 ArrayBuffer 中:
```js
const ta = new Uint8Array(4); // 4 elements
assert.deepEqual(
ta.buffer, new ArrayBuffer(4)); // 4 bytes
```
* 使用零初始化類型化數組:
* `new Array(4)`創建一個沒有任何元素的普通數組。它只有 4 個 _ 孔 _(小于`.length`的指數沒有相關元素)。
* `new Uint8Array(4)`創建一個 Typed Array,其中 4 個元素都為 0。
```js
assert.deepEqual(new Uint8Array(4), Uint8Array.of(0, 0, 0, 0));
```
* Typed Array 的所有元素都具有相同的類型:
* 設置元素將值轉換為該類型。
```js
const ta = new Uint8Array(1);
ta[0] = 256;
assert.equal(ta[0], 0);
ta[0] = '2';
assert.equal(ta[0], 2);
```
* 獲取元素返回數字。
```js
const ta = new Uint8Array(1);
assert.equal(ta[0], 0);
assert.equal(typeof ta[0], 'number');
```
* Typed Array 的`.length`派生自其 ArrayBuffer 并且永遠不會更改(除非您切換到不同的 ArrayBuffer)。
* 普通數組可以有孔;鍵入的數組不能。
#### 29.4.2。類型化數組是可迭代的
類型數組是[可迭代的](ch_sync-iteration.html)。這意味著您可以使用`for-of`循環和類似的機制:
```js
const ui8 = Uint8Array.of(0,1,2);
for (const byte of ui8) {
console.log(byte);
}
// Output:
// 0
// 1
// 2
```
ArrayBuffers 和 DataViews 不可迭代。
#### 29.4.3。將類型化數組轉換為普通數組
要將普通數組轉換為類型化數組,請將其傳遞給類型化數組構造函數。例如:
```js
const tarr = new Uint8Array([0,1,2]);
```
要將 Typed Array 轉換為普通 Array,可以使用 spread 或`Array.from()`(因為 Typed Arrays 是可迭代的):
```js
assert.deepEqual([...tarr], [0,1,2]);
assert.deepEqual(Array.from(tarr), [0,1,2]);
```
#### 29.4.4。 Typed Arrays 的類層次結構
各種 Typed Array 對象的屬性分兩步介紹:
1. `TypedArray`:首先,我們看一下所有 Typed Array 類的公共超類(在本章開頭的類圖[中顯示)。我正在調用超類`TypedArray`,但它不能直接從 JavaScript 訪問。 `TypedArray.prototype`包含 Typed Arrays 的所有方法。](#fig:typed_arrays_class_diagram)
2. `?ElementType?Array`:實際的 Typed Array 類稱為`Uint8Array`,`Int16Array`,`Float32Array`等。
#### 29.4.5。 `TypedArray`的靜態方法
靜態`TypedArray`方法都由其子類(`Uint8Array`等)繼承。
##### 29.4.5.1。 `TypedArray.of()`
此方法具有類型簽名:
```js
.of(...items: number[]): instanceof this
```
返回類型的表示法是我的發明:`.of()`返回`this`的實例(調用`of()`的類)。實例的元素是`of()`的參數。
您可以將`of()`視為 Typed Arrays 的自定義字面值:
```js
const float32Arr = Float32Array.of(0.151, -8, 3.7);
const int16Arr = Int32Array.of(-10, 5, 7);
```
##### 29.4.5.2。 `TypedArray.from()`
此方法具有類型簽名:
```js
TypedArray<T>.from<S>(
source: Iterable<S>|ArrayLike<S>, mapfn?: S => T, thisArg?: any)
: instanceof this
```
它將`source`轉換為`this`(類型化數組)的實例。再一次,語法`instanceof this`是我的發明。
例如,普通數組是可迭代的,可以使用此方法轉換:
```js
assert.deepEqual(
Uint16Array.from([0, 1, 2]),
Uint16Array.of(0, 1, 2));
```
類型化數組也是可迭代的:
```js
assert.deepEqual(
Uint16Array.from(Uint8Array.of(0, 1, 2)),
Uint16Array.of(0, 1, 2));
```
`source`也可以是[類似于數組的對象](ch_arrays.html#array-like-objects):
```js
assert.deepEqual(
Uint16Array.from({0:0, 1:1, 2:2, length: 3}),
Uint16Array.of(0, 1, 2));
```
可選的`mapfn`允許您在`source`成為結果元素之前對其進行轉換。為什么一次執行兩個步驟 _ 映射 _ 和 _ 轉換 _?與通過`.map()`單獨映射相比,有兩個優點:
1. 不需要中間數組或類型數組。
2. 在具有不同精度的類型化數組之間進行轉換時,可能會出現更少的錯誤。
為了說明第二個優點,我們首先將 Typed 數組轉換為具有更高精度的 Typed 數組。如果我們使用`.from()`進行映射,結果會自動更正。否則,您必須先轉換然后映射。
```js
const typedArray = Int8Array.of(127, 126, 125);
assert.deepEqual(
Int16Array.from(typedArray, x => x * 2),
Int16Array.of(254, 252, 250));
assert.deepEqual(
Int16Array.from(typedArray).map(x => x * 2),
Int16Array.of(254, 252, 250)); // OK
assert.deepEqual(
Int16Array.from(typedArray.map(x => x * 2)),
Int16Array.of(-2, -4, -6)); // wrong
```
如果我們從類型化數組轉換為具有較低精度的類型化數組,則通過`.from()`進行映射會產生正確的結果。否則,我們必須首先映射然后轉換。
```js
assert.deepEqual(
Int8Array.from(Int16Array.of(254, 252, 250), x => x / 2),
Int8Array.of(127, 126, 125));
assert.deepEqual(
Int8Array.from(Int16Array.of(254, 252, 250).map(x => x / 2)),
Int8Array.of(127, 126, 125)); // OK
assert.deepEqual(
Int8Array.from(Int16Array.of(254, 252, 250)).map(x => x / 2),
Int8Array.of(-1, -2, -3)); // wrong
```
問題是,如果我們通過`.map()`進行映射,那么輸入類型和輸出類型是相同的(如果我們使用 Typed Arrays)。相反,`.from()`從任意輸入類型變為您通過其接收器指定的輸出類型。
[根據 Allen Wirfs-Brock](https://twitter.com/awbjs/status/585199958661472257) ,Typed Arrays 之間的映射是`.from()`的`mapfn`參數的動機。
#### 29.4.6。 `TypedArray<T>.prototype`的屬性
Typed Array 方法接受的索引可能是否定的(它們就像傳統的 Array 方法一樣)。偏移必須是非負的。有關詳細信息,請參見[“指數和偏移”](ch_typed-arrays.html#typed-arrays-indices-offsets)部分。
##### 29.4.6.1。 Typed Arrays 特有的屬性
以下屬性特定于 Typed Arrays;普通數組沒有它們:
* `get .buffer(): ArrayBuffer`
返回支持此 Typed Array 的緩沖區。
* `get .length(): number`
返回此 Typed Array 緩沖區元素的長度。請注意,普通數組的長度不是 getter,它是實例具有的特殊屬性。
* `get .byteLength(): number`
返回此 Typed Array 緩沖區的大小(以字節為單位)。
* `get .byteOffset(): number`
返回此 Arrayd Array 在其 ArrayBuffer 中“啟動”的偏移量。
* `.set(arrayLike: ArrayLike<number>, offset=0): void`
* `.set(typedArray: TypedArray, offset=0): void`將第一個參數的所有元素復制到此 Typed 數組。參數索引 0 處的元素被寫入此類型數組的索引`offset`(等)。
* 第一個參數是`arrayLike`:它的元素被轉換為數字,然后轉換為此類型數組的元素類型`T`。
* 第一個參數是`typedArray`:它的每個元素都直接轉換為此類型數組的相應類型。如果兩個 Typed Arrays 具有相同的元素類型然后更快,則使用逐字節復制。
* `.subarray(startIndex=0, end=this.length): TypedArray<T>`
返回一個新的 Typed Array,它與此 Typed Array 具有相同的緩沖區,但是(通常)較小的范圍。如果`startIndex`為非負數,則生成的類型化數組的第一個元素為`this[startIndex]`,第二個`this[startIndex+1]`(等)。如果`startIndex`為負數,則進行適當轉換。
##### 29.4.6.2。數組方法
以下方法與普通數組的方法基本相同:
* `.copyWithin(target: number, start: number, end=this.length): this` <sup>[W,ES6]</sup>
* `.entries(): Iterable<[number, T]>` <sup>[R,ES6]</sup>
* `.every(callback: (value: T, index: number, array: TypedArray<T>) => boolean, thisArg?: any): boolean` <sup>[R,ES5]</sup>
* `.fill(value: T, start=0, end=this.length): this` <sup>[W,ES6]</sup>
* `.filter(callback: (value: T, index: number, array: TypedArray<T>) => any, thisArg?: any): T[]` <sup>[R,ES5]</sup>
* `.find(predicate: (value: T, index: number, obj: T[]) => boolean, thisArg?: any): T | undefined` <sup>[R,ES6]</sup>
* `.findIndex(predicate: (value: T, index: number, obj: T[]) => boolean, thisArg?: any): number` <sup>[R,ES6]</sup>
* `.forEach(callback: (value: T, index: number, array: TypedArray<T>) => void, thisArg?: any): void` <sup>[R,ES5]</sup>
* `.includes(searchElement: T, fromIndex=0): boolean` <sup>[R,ES2016]</sup>
* `.indexOf(searchElement: T, fromIndex=0): number` <sup>[R,ES5]</sup>
* `.join(separator = ','): string` <sup>[R,ES1]</sup>
* `.keys(): Iterable<number>` <sup>[R,ES6]</sup>
* `.lastIndexOf(searchElement: T, fromIndex=this.length-1): number` <sup>[R,ES5]</sup>
* `.map<U>(mapFunc: (value: T, index: number, array: TypedArray<T>) => U, thisArg?: any): U[]` <sup>[R,ES5]</sup>
* `.reduce<U>(callback: (accumulator: U, element: T, index: number, array: T[]) => U, init?: U): U` <sup>[R,ES5]</sup>
* `.reduceRight<U>(callback: (accumulator: U, element: T, index: number, array: T[]) => U, init?: U): U` <sup>[R,ES5]</sup>
* `.reverse(): this` <sup>[W,ES1]</sup>
* `.slice(start=0, end=this.length): T[]` <sup>[R,ES3]</sup>
* `.some(callback: (value: T, index: number, array: TypedArray<T>) => boolean, thisArg?: any): boolean` <sup>[R,ES5]</sup>
* `.sort(compareFunc?: (a: T, b: T) => number): this` <sup>[W,ES1]</sup>
* `.toString(): string` <sup>[R,ES1]</sup>
* `.values(): Iterable<number>` <sup>[R,ES6]</sup>
有關這些方法如何工作的詳細信息,請參閱[關于普通數組](ch_arrays.html#quickref-array-prototype)的章節。
#### 29.4.7。 `new ?ElementType?Array()`
每個 Typed Array 構造函數的名稱都遵循模式`?ElementType?Array`,其中`?ElementType?`是開頭表格中的元素類型之一。這意味著有 9 個類型數組的構造函數:`Int8Array`,`Uint8Array`,`Uint8ClampedArray`(元素類型`Uint8C`),`Int16Array`,`Uint16Array`,`Int32Array`,`Uint32Array`,`Float32Array`, `Float64Array`。
每個構造函數都有四個 _ 重載 _ 版本 - 它的行為會有所不同,具體取決于它接收的參數數量以及它們的類型:
* `new ?ElementType?Array(buffer: ArrayBuffer, byteOffset=0, length=0)`
創建一個新的`?ElementType?Array`,其緩沖區為`buffer`。它開始訪問給定`byteOffset`的緩沖區,并具有給定的`length`。請注意,`length`計算 Typed Array 的元素(每個 1-4 字節),而不是字節。
* `new ?ElementType?Array(length=0)`
使用給定的`length`和相應的緩沖區(其大小以字節為`length * ?ElementType?Array.BYTES_PER_ELEMENT`)創建新的`?ElementType?Array`。
* `new ?ElementType?Array(source: TypedArray)`
創建`?ElementType?Array`的新實例,其元素與`source`的元素具有相同的值,但強制為`ElementType`。
* `new ?ElementType?Array(source: ArrayLike<number>)`
創建`?ElementType?Array`的新實例,其元素與`source`的元素具有相同的值,但強制為`ElementType`。 (有關類似數組的對象的更多信息,請參閱[關于數組](ch_arrays.html#array-like-objects)的章節。)
以下代碼顯示了創建相同 Typed 數組的三種不同方法:
```js
const ta1 = new Uint8Array([0, 1, 2]);
const ta2 = Uint8Array.of(0, 1, 2);
const ta3 = new Uint8Array(3);
ta3[0] = 0;
ta3[1] = 1;
ta3[2] = 2;
assert.deepEqual(ta1, ta2);
assert.deepEqual(ta1, ta3);
```
#### 29.4.8。 `?ElementType?Array`的靜態屬性
* `?ElementType?Array.BYTES_PER_ELEMENT: number`
計算存儲單個元素需要多少字節:
```js
> Uint8Array.BYTES_PER_ELEMENT
1
> Int16Array.BYTES_PER_ELEMENT
2
> Float64Array.BYTES_PER_ELEMENT
8
```
#### 29.4.9。 `?ElementType?Array.prototype`的屬性
* `.BYTES_PER_ELEMENT: number`
與`?ElementType?Array.BYTES_PER_ELEMENT`相同。
#### 29.4.10。連接類型數組
類型數組沒有方法`.concat()`,就像普通數組那樣。解決方法是使用該方法
```js
.set(typedArray: TypedArray, offset=0): void
```
該方法將現有的 Typed Array 復制到索引`offset`的`typedArray`中。然后你只需要確保`typedArray`足夠大以容納你想要連接的所有(Typed)數組:
```js
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;
}
assert.deepEqual(
concatenate(Uint8Array,
Uint8Array.of(1, 2), [3, 4]),
Uint8Array.of(1, 2, 3, 4)
);
```
### 29.5。 DataViews 的
#### 29.5.1。 `new DataView()`
* `new DataView(buffer: ArrayBuffer, byteOffset=0, byteLength=buffer.byteLength-byteOffset)`
創建一個新的 DataView,其數據存儲在 ArrayBuffer `buffer`中。默認情況下,新的 DataView 可以訪問所有`buffer`,最后兩個參數允許您更改它。
#### 29.5.2。 `DataView.prototype`的屬性
`?ElementType?`可以是:`Float32`,`Float64`,`Int8`,`Int16`,`Int32`,`Uint8`,`Uint16`,`Uint32`。
* `get .buffer()`
返回此 DataView 的 ArrayBuffer。
* `get .byteLength()`
返回此 DataView 可以訪問的字節數。
* `get .byteOffset()`
返回此 DataView 開始訪問其緩沖區中的字節的偏移量。
* `.get?ElementType?(byteOffset: number, littleEndian=false)`
從此 DataView 的緩沖區中讀取值。
* `.set?ElementType?(byteOffset: number, value: number, littleEndian=false)`
將`value`寫入此 DataView 的緩沖區。
### 29.6。進一步閱讀
[“探索 ES6”中關于類型化數組](http://exploringjs.com/es6/ch_typed-arrays.html)的章節還有一些額外的內容:
* 有關支持 Typed Arrays 的瀏覽器 API 的更多詳細信息
* 一個現實世界的例子
* 還有一些技術細節。
- I.背景
- 1.關于本書(ES2019 版)
- 2.常見問題:本書
- 3. JavaScript 的歷史和演變
- 4.常見問題:JavaScript
- II.第一步
- 5.概覽
- 6.語法
- 7.在控制臺上打印信息(console.*)
- 8.斷言 API
- 9.測驗和練習入門
- III.變量和值
- 10.變量和賦值
- 11.值
- 12.運算符
- IV.原始值
- 13.非值undefined和null
- 14.布爾值
- 15.數字
- 16. Math
- 17. Unicode - 簡要介紹(高級)
- 18.字符串
- 19.使用模板字面值和標記模板
- 20.符號
- V.控制流和數據流
- 21.控制流語句
- 22.異常處理
- 23.可調用值
- VI.模塊化
- 24.模塊
- 25.單個對象
- 26.原型鏈和類
- 七.集合
- 27.同步迭代
- 28.數組(Array)
- 29.類型化數組:處理二進制數據(高級)
- 30.映射(Map)
- 31. WeakMaps(WeakMap)
- 32.集(Set)
- 33. WeakSets(WeakSet)
- 34.解構
- 35.同步生成器(高級)
- 八.異步
- 36. JavaScript 中的異步編程
- 37.異步編程的 Promise
- 38.異步函數
- IX.更多標準庫
- 39.正則表達式(RegExp)
- 40.日期(Date)
- 41.創建和解析 JSON(JSON)
- 42.其余章節在哪里?