溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

使用JavaScript怎么讀寫二進(jìn)制數(shù)據(jù)

發(fā)布時(shí)間:2021-05-19 17:37:39 來源:億速云 閱讀:138 作者:Leah 欄目:web開發(fā)

本篇文章為大家展示了使用JavaScript怎么讀寫二進(jìn)制數(shù)據(jù),內(nèi)容簡明扼要并且容易理解,絕對(duì)能使你眼前一亮,通過這篇文章的詳細(xì)介紹希望你能有所收獲。

類型化數(shù)組的出現(xiàn)

類型化數(shù)組是 HTML5 中引入的API,它能夠讓開發(fā)者使用 JavaScript 直接操作二進(jìn)制數(shù)據(jù)。在類型化數(shù)組出現(xiàn)之前,我們是無法直接通過 JavaScript 操作二進(jìn)制數(shù)據(jù),通常都是操作 JavaScript 中的數(shù)據(jù)類型,由運(yùn)行時(shí)轉(zhuǎn)化成二進(jìn)制。這就多了一個(gè)轉(zhuǎn)化的過程,盡管 JavaScript 對(duì)數(shù)據(jù)類型做了很多優(yōu)化以提高效率,但相比直接操作二進(jìn)制來說,仍然有效率上的差異。于是類型化數(shù)組就順勢(shì)推出了。

用途

那么,類型化數(shù)組的應(yīng)用場(chǎng)景都有哪些呢?

  • canvas 圖像處理。

  • WebGL 與顯卡通信。

  • 文件操作

  • Ajax響應(yīng)

如何使用

那么,既然類型化數(shù)組這么重要,那還等什么,趕緊來掌握它們吧。

既然我們要直接操作二進(jìn)制數(shù)據(jù),二進(jìn)制數(shù)據(jù)又是存放在一段連續(xù)的內(nèi)存區(qū)域中,所以我們首先要有這么一段內(nèi)存區(qū)域。

我們可以創(chuàng)建一個(gè)內(nèi)存區(qū)域:

let buffer = new ArrayBuffer()

ArrayBuffer 是一個(gè)構(gòu)造函數(shù),允許我們實(shí)例化數(shù)組緩沖區(qū),數(shù)組緩沖區(qū)可以理解為是一段連續(xù)的內(nèi)存區(qū)域。

由于我們構(gòu)造函數(shù)傳入的參數(shù)是空,所以生成的 buffer 指向的內(nèi)存長度是 0 字節(jié),沒有意義。

嗯,那我們就創(chuàng)建一個(gè)有意義的內(nèi)存區(qū)域。

buffer = new ArrayBuffer(8)

我們給ArrayBuffer 傳入?yún)?shù) 8,意思是讓瀏覽器幫我們創(chuàng)建一段 8 個(gè)字節(jié)長度的內(nèi)存區(qū)域。

我們看下這段內(nèi)存區(qū)域的長度是否是 8 個(gè)字節(jié)

console.log(buffer.byteLength);

輸出是 8, 看來瀏覽器沒有欺騙我們。

使用JavaScript怎么讀寫二進(jìn)制數(shù)據(jù)

我們猜想這 8 個(gè)字節(jié)里面的值應(yīng)該都是 0 ,因?yàn)槲覀儾]有給 buffer 賦值。讓我們確認(rèn)一下吧,先看第一個(gè)字節(jié):

console.log(buffer[0])

輸出: undefined。

咦?怎么是 undefined 呢?

哦,原來 buffer[0] 的意思是查看 buffer 這個(gè)對(duì)象 的屬性為 0 的值,因?yàn)?buffer 沒有 0 這個(gè)屬性,所以是 undefined。

好吧,看來我們查看 buffer 內(nèi)容的姿勢(shì)不對(duì)。

那該如何查看 buffer 內(nèi)容呢?

數(shù)組視圖

珰珰珰珰,八大金剛閃亮登場(chǎng)~

Int8Array:8 位有符號(hào)整數(shù),長度 1 個(gè)字節(jié)。
Uint8Array: 8位無符號(hào)整數(shù), 1 個(gè)字節(jié)長度。
Int16Array:16位有符號(hào)整數(shù), 2 個(gè)字節(jié)長度。
Uint16Array:16位無符號(hào)整數(shù),2 個(gè)字節(jié)長度。
Int32Array:32位有符號(hào)整數(shù), 4 個(gè)字節(jié)長度。
Uint32Array:32位無符號(hào)整數(shù), 4 個(gè)字節(jié)長度。
Float32Array:32位浮點(diǎn)數(shù), 4 個(gè)字節(jié)長度。
Float64Array:64位浮點(diǎn)數(shù),8 個(gè)字節(jié)長度。

這八大金剛有什么神通呢?我們無法直接讀寫 buffer 數(shù)據(jù),而這八種數(shù)據(jù)類型充當(dāng)了讀寫 buffer 內(nèi)容的橋梁。

使用JavaScript怎么讀寫二進(jìn)制數(shù)據(jù)

還是上面的 buffer,我們想查看一下 buffer 內(nèi)容。首先創(chuàng)建一個(gè)讀寫該 buffer 的橋梁:

let int8Array = new Int8Array(buffer);

我們創(chuàng)建了一個(gè)讀寫 buffer 的橋梁,用 8 位有符號(hào)整數(shù)來讀寫 buffer。那現(xiàn)在我們看看 buffer 第一位的內(nèi)容是什么吧?

console.log(int8Array[0]);

輸出:0,看來初始化的時(shí)候,buffer 的各個(gè)字節(jié)存儲(chǔ)的值默認(rèn)都是 0 了。

使用JavaScript怎么讀寫二進(jìn)制數(shù)據(jù)

我們看看如何使用 Int8Array 給 buffer 賦值:

int8Array[0] = 30;
int8Array[1] = 41;

int8Array[2] = 52;
int8Array[3] = 63;

int8Array[4] = 74;
int8Array[5] = 85;

int8Array[6] = 86;
int8Array[7] = 97;

很簡單,因?yàn)?Int8Array 是一個(gè)字節(jié)的長度,和 buffer 的單位一致,所以我們可以通過索引的形式對(duì) buffer 指定位置進(jìn)行賦值操作。

使用JavaScript怎么讀寫二進(jìn)制數(shù)據(jù)

很簡單吧?就是這么簡單。

另外七大金剛和 Int8Array 的用法一樣,但是有所不同,我們看下他們之間的區(qū)別。

這次我們使用 Int16Array,仍然是剛才的 buffer,我們創(chuàng)建一個(gè)新的橋梁,這座橋梁仍然通往 buffer 。

let int16Array = new Int16Array(buffer);

大家試想一下 int16Array[0] 是什么內(nèi)容?

我們輸出一下:

console.log(int16Array[0])

咦,結(jié)果怎么是 10526?

不太理解了。好吧,我們分析下 10526 怎么得來的。

我們看下 buffer 中的二進(jìn)制數(shù)據(jù)。

由于 Int16Array 占兩個(gè)字節(jié),所以我們?cè)谟盟x寫數(shù)據(jù)的時(shí)候,一個(gè)索引所代表的數(shù)據(jù)等于 buffer 中兩個(gè)字節(jié)。

使用JavaScript怎么讀寫二進(jìn)制數(shù)據(jù)

我們可以看到 int16Array[0] 里面的二進(jìn)制數(shù)據(jù)是由30的二進(jìn)制和41的二進(jìn)制數(shù)據(jù)拼接而成:00011110(30)  00101001(41)。

我們按照 30、41的順序計(jì)算一下二進(jìn)制對(duì)應(yīng)的十進(jìn)制數(shù)。

parseInt(1111000101001, 2) //輸出 7721

算出來的值是 7721,這和我們輸出的不一致呀?

這就涉及到字節(jié)順序的概念。在我們的個(gè)人筆記本上一般都是小端字節(jié)序。小端字節(jié)序體現(xiàn)在我們這個(gè)示例中即是 41、30的二進(jìn)制順序,我們剛才的計(jì)算順序有問題,那按照 41、30 的二進(jìn)制順序計(jì)算一下

parseInt(10100100011110, 2) //輸出 10526

可以看到輸出結(jié)果是 10526,和我們直接使用 int16Array[0]

得出的結(jié)果一致。

上面這個(gè)例子,告訴我們?cè)趽Q數(shù)據(jù)結(jié)構(gòu)解析 buffer 的時(shí)候,數(shù)據(jù)會(huì)變得不容易理解,我們一定要謹(jǐn)慎處理。

屬性和方法

類型化數(shù)組實(shí)例化的對(duì)象包含一些很有用的屬性和方法:

length

length屬性返回類型化數(shù)組的數(shù)據(jù)成員個(gè)數(shù)。

byteLength

返回類型化數(shù)組的字節(jié)長度。注意與length的區(qū)別。通長 byteLength = length * 每個(gè)數(shù)據(jù)占用字節(jié)數(shù)

byteOffset

返回該類型化數(shù)組的數(shù)據(jù)從所處 buffer 中的哪個(gè)字節(jié)開始。

buffer

類型化數(shù)組對(duì)應(yīng)的 buffer。

set

復(fù)制數(shù)組,將某段內(nèi)存中的數(shù)據(jù)完整地復(fù)制到另一段內(nèi)存。

let a = new Uint8Array(12);
a[0] = 31;
a[1] = 32;
let b = new Uint8Array(12);
b.set(a);

上面這段代碼的意思是將 a 這段buffer中的內(nèi)容,完整地拷貝到 b 這段 buffer 中,這種方式比按索引賦值要快速地多。
當(dāng)然,set 支持從某個(gè)索引開始復(fù)制數(shù)據(jù)

let a = new Uint8Array(12);
a[0] = 31;
a[1] = 32;
let b = new Uint8Array(10);
b.set(a, 2);

上面這段代碼意思是從b的第三個(gè)索引位置開始復(fù)制 a 中的數(shù)據(jù)。

subarray

subarray的意思是對(duì)一個(gè)類型化數(shù)組,取其子數(shù)組的內(nèi)容,返回一個(gè)新的類型化數(shù)組。

let a = new Uint8Array(8);
a[2] = 1;
let b = a.subarray(2,3);
console.log(b.length);
console.log(b.byteLength);

subarray 的第一個(gè)參數(shù),代表從源數(shù)組的第幾個(gè)索引開始截取,第二個(gè)參數(shù)代表截取到第幾個(gè)索引。

混合視圖

有一點(diǎn)需要注意,我們的類型數(shù)組初始化的時(shí)候,可以指定 buffer的某一段,這就意味著,我們可以對(duì)一段 buffer 內(nèi)存區(qū)域指定多個(gè)類型數(shù),我們稱之為 混合視圖。

let buffer = new Buffer(8);
let idArray = new Int8Array(buffer, 0,2);
let nameArray = new Int8Array(buffer, 2, 4);
let ageArray = new Int8Array(buffer, 6, 2);

我們用一段內(nèi)存區(qū)域表示一個(gè)人的 id、name、age。這種結(jié)構(gòu)類似于 C 語言中的 struct 。

使用JavaScript怎么讀寫二進(jìn)制數(shù)據(jù)

我們將一段 8 個(gè)字節(jié)的內(nèi)存分成三個(gè)部分:

  • 字節(jié) 0 ~ 字節(jié) 1 代表 id。

  • 字節(jié) 2 ~ 字節(jié) 5 代表 username。

  • 字節(jié) 6 ~ 字節(jié) 7 代表 age。

DataView

JavaScript 還引入了另外種視圖DataView,也能達(dá)到操作 buffer 的目的,但相比之下,DataView 操作粒度更細(xì)一些,而且還能夠設(shè)置字節(jié)序?yàn)榇蠖诉€是小端。

DataView 的構(gòu)造函數(shù):

DataView(ArrayBuffer對(duì)象 buffer, 從 buffer 的第幾個(gè)字節(jié)開始讀取, 讀取的長度);

舉個(gè)例子來說:

let buffer = new ArrayBuffer(10);
let view = new DataView(buffer);

如何讀???

我們創(chuàng)建好了視圖 view, 那該如何讀取呢?

  • getInt8(index, order):從第 index 個(gè)字節(jié)讀取一個(gè) 8 位整數(shù)。

  • getUint8(index, order):從第 index 個(gè)字節(jié)開始讀取一個(gè)無符號(hào)的 8 位整數(shù)。

  • getInt16(index, order):從第 index 個(gè)字節(jié)開始讀取 2 個(gè)字節(jié),返回一個(gè) 16 位整數(shù)。

  • getUint16(index, order):從第 index 個(gè)字節(jié)開始讀取 2 個(gè)字節(jié),返回一個(gè)無符號(hào)的 16 位整數(shù)。

  • getInt32(index, order):從第 index 個(gè)字節(jié)開始讀取 4 個(gè)字節(jié),返回一個(gè)32位的整數(shù)。

  • getUint32(index, order):從第 index 個(gè)字節(jié)開始讀取 4 個(gè)字節(jié),返回一個(gè)無符號(hào)的 32 位整數(shù)。

  • getFloat32(index, order):從第 index 個(gè)字節(jié)開始讀取 4 個(gè)字節(jié),返回一個(gè) 32 位 浮點(diǎn)數(shù)。

  • getFloat64(index, order):從第 index 個(gè)字節(jié)開始讀取 8 個(gè)字節(jié),返回一個(gè) 64 位的浮點(diǎn)數(shù)。

JavaScript 提供了 8 種讀取方式,功能很簡單,也很容易理解,這里就不一一做示例了,大家可以自己試一下。

剛剛我們也說了,DataView 也支持設(shè)置字節(jié)序,在上面 8 中讀取方式中,第一個(gè)字節(jié)是索引,第二個(gè)字節(jié)允許我們?cè)O(shè)置字節(jié)序,true 代表 小端字節(jié)序讀取,false 代表大端字節(jié)序讀取,默認(rèn)為 false。

如何寫入?

DataView 不僅能支持細(xì)粒度的讀取操作,也支持細(xì)粒度的寫入操作:

  • setInt8(index, value, order):從第 index 個(gè)字節(jié)開始,寫入 1 個(gè)字節(jié)的值為 value 的 8 位整數(shù)。

  • setUint8(index, value, order):從第 index 個(gè)字節(jié)開始,寫入 1 個(gè)字節(jié)的值為 value 的無符號(hào) 8 位整數(shù)。

  • setInt16(index, value, order):從第 index 個(gè)字節(jié)開始,寫入 2 個(gè)字節(jié)的值為 value 的 16 位整數(shù)。

  • setUint16(index, value, order):從第 index 個(gè)字節(jié)開始,寫入 2 個(gè)字節(jié)的值為 value 的無符號(hào)的 16 位整數(shù)。

  • setInt32(index, value, order):從第 index 個(gè)字節(jié)開始,寫入 4 個(gè)字節(jié)的值為 value 的 32 位整數(shù)。

  • setUint32(index, value, order):從第 index 個(gè)字節(jié)開始,寫入 4 個(gè)字節(jié)的值為 value 的無符號(hào) 32 位整數(shù)。

  • setFloat32(index, value, order):從第 index 個(gè)字節(jié)開始,寫入 4  個(gè)字節(jié)的值為 value 的 32 位浮點(diǎn)數(shù)。

  • setFloat64(index, value, order):從第 index 個(gè)字節(jié)開始,寫入 8  個(gè)字節(jié)的值為 value 的 64 位浮點(diǎn)數(shù)。

JavaScript是什么

JS是JavaScript的簡稱,它是一種直譯式的腳本語言,其解釋器被稱為JavaScript引擎,是瀏覽器的一部分,主要用于web的開發(fā),可以給網(wǎng)站添加各種各樣的動(dòng)態(tài)效果,讓網(wǎng)頁更加美觀。

上述內(nèi)容就是使用JavaScript怎么讀寫二進(jìn)制數(shù)據(jù),你們學(xué)到知識(shí)或技能了嗎?如果還想學(xué)到更多技能或者豐富自己的知識(shí)儲(chǔ)備,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI