ArrayBuffer對象、TypedArray視圖和DataView視圖


轉:http://es6.ruanyifeng.com/#docs/arraybuffer

ArrayBuffer

ArrayBuffer對象、TypedArray視圖和DataView視圖是 JavaScript 操作二進制數據的一個接口。這些對象早就存在,屬於獨立的規格(2011 年 2 月發布),ES6 將它們納入了 ECMAScript 規格,並且增加了新的方法。它們都是以數組的語法處理二進制數據,所以統稱為二進制數組。

這個接口的原始設計目的,與 WebGL 項目有關。所謂 WebGL,就是指瀏覽器與顯卡之間的通信接口,為了滿足 JavaScript 與顯卡之間大量的、實時的數據交換,它們之間的數據通信必須是二進制的,而不能是傳統的文本格式。文本格式傳遞一個 32 位整數,兩端的 JavaScript 腳本與顯卡都要進行格式轉化,將非常耗時。這時要是存在一種機制,可以像 C 語言那樣,直接操作字節,將 4 個字節的 32 位整數,以二進制形式原封不動地送入顯卡,腳本的性能就會大幅提升。

二進制數組就是在這種背景下誕生的。它很像 C 語言的數組,允許開發者以數組下標的形式,直接操作內存,大大增強了 JavaScript 處理二進制數據的能力,使得開發者有可能通過 JavaScript 與操作系統的原生接口進行二進制通信。

二進制數組由三類對象組成。

(1)ArrayBuffer對象:代表內存之中的一段二進制數據,可以通過“視圖”進行操作。“視圖”部署了數組接口,這意味着,可以用數組的方法操作內存。

(2)TypedArray視圖:共包括 9 種類型的視圖,比如Uint8Array(無符號 8 位整數)數組視圖, Int16Array(16 位整數)數組視圖, Float32Array(32 位浮點數)數組視圖等等。

(3)DataView視圖:可以自定義復合格式的視圖,比如第一個字節是 Uint8(無符號 8 位整數)、第二、三個字節是 Int16(16 位整數)、第四個字節開始是 Float32(32 位浮點數)等等,此外還可以自定義字節序。

簡單說,ArrayBuffer對象代表原始的二進制數據,TypedArray 視圖用來讀寫簡單類型的二進制數據,DataView視圖用來讀寫復雜類型的二進制數據。

TypedArray 視圖支持的數據類型一共有 9 種(DataView視圖支持除Uint8C以外的其他 8 種)。

數據類型 字節長度 含義 對應的 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

注意,二進制數組並不是真正的數組,而是類似數組的對象。

很多瀏覽器操作的 API,用到了二進制數組操作二進制數據,下面是其中的幾個。

  • File API
  • XMLHttpRequest
  • Fetch API
  • Canvas
  • WebSockets

ArrayBuffer 對象

概述

ArrayBuffer對象代表儲存二進制數據的一段內存,它不能直接讀寫,只能通過視圖(TypedArray視圖和DataView視圖)來讀寫,視圖的作用是以指定格式解讀二進制數據。

ArrayBuffer也是一個構造函數,可以分配一段可以存放數據的連續內存區域。

const buf = new ArrayBuffer(32); 

上面代碼生成了一段 32 字節的內存區域,每個字節的值默認都是 0。可以看到,ArrayBuffer構造函數的參數是所需要的內存大小(單位字節)。

為了讀寫這段內容,需要為它指定視圖。DataView視圖的創建,需要提供ArrayBuffer對象實例作為參數。

const buf = new ArrayBuffer(32); const dataView = new DataView(buf); dataView.getUint8(0) // 0 

上面代碼對一段 32 字節的內存,建立DataView視圖,然后以不帶符號的 8 位整數格式,從頭讀取 8 位二進制數據,結果得到 0,因為原始內存的ArrayBuffer對象,默認所有位都是 0。

另一種 TypedArray 視圖,與DataView視圖的一個區別是,它不是一個構造函數,而是一組構造函數,代表不同的數據格式。

const buffer = new ArrayBuffer(12); const x1 = new Int32Array(buffer); x1[0] = 1; const x2 = new Uint8Array(buffer); x2[0] = 2; x1[0] // 2 

上面代碼對同一段內存,分別建立兩種視圖:32 位帶符號整數(Int32Array構造函數)和 8 位不帶符號整數(Uint8Array構造函數)。由於兩個視圖對應的是同一段內存,一個視圖修改底層內存,會影響到另一個視圖。

TypedArray 視圖的構造函數,除了接受ArrayBuffer實例作為參數,還可以接受普通數組作為參數,直接分配內存生成底層的ArrayBuffer實例,並同時完成對這段內存的賦值。

const typedArray = new Uint8Array([0,1,2]); typedArray.length // 3 typedArray[0] = 5; typedArray // [5, 1, 2] 

上面代碼使用 TypedArray 視圖的Uint8Array構造函數,新建一個不帶符號的 8 位整數視圖。可以看到,Uint8Array直接使用普通數組作為參數,對底層內存的賦值同時完成。

ArrayBuffer.prototype.slice() 

ArrayBuffer實例有一個slice方法,允許將內存區域的一部分,拷貝生成一個新的ArrayBuffer對象。

const buffer = new ArrayBuffer(8); const newBuffer = buffer.slice(0, 3); 

上面代碼拷貝buffer對象的前 3 個字節(從 0 開始,到第 3 個字節前面結束),生成一個新的ArrayBuffer對象。slice方法其實包含兩步,第一步是先分配一段新內存,第二步是將原來那個ArrayBuffer對象拷貝過去。

slice方法接受兩個參數,第一個參數表示拷貝開始的字節序號(含該字節),第二個參數表示拷貝截止的字節序號(不含該字節)。如果省略第二個參數,則默認到原ArrayBuffer對象的結尾。

除了slice方法,ArrayBuffer對象不提供任何直接讀寫內存的方法,只允許在其上方建立視圖,然后通過視圖讀寫


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM