之前在某個專案中,遇到了許多JS的二進位制操作場景,因此總結下JS中的二進位制操作方法。
所謂二進位制操作,是指操作變數實際儲存的值,比如獲取字元A
的Unicode值,或者將值100填入到8個位元組中。
1. 位操作符
JS中的位操作與很多語言類似,具體的位運算子如下表所示。
運算子 | 用法 | 描述 |
---|---|---|
按位與 | a & b | 對於每一個位元位,只有兩個運算元相應的位元位都是1時,結果才為1,否則為0。 |
按位或 | a | b | 對於每一個位元位,當兩個運算元相應的位元位至少有一個1時,結果為1,否則為0。 |
按位異或 | a ^ b | 對於每一個位元位,當兩個運算元相應的位元位有且只有一個1時,結果為1,否則為0。 |
按位非 | ~ a | 反轉運算元的位元位,即0變成1,1變成0。 |
左移 | a << b | 將 a 的二進位制形式向左移 b (< 32) 位元位,右邊用0填充。 |
有符號右移 | a >> b | 將 a 的二進位制表示向右移 b (< 32) 位,丟棄被移出的位。 |
無符號右移 | a >>> b | 將 a 的二進位制表示向右移 b (< 32) 位,丟棄被移出的位,並使用 0 在左側填充。 |
2. 字元和Unicode編碼
在介紹具體的方法前,我們需要先了解下UCS-2和UTF-16編碼。
UCS-2是一個16bit長度的編碼集,它的表示範圍是0到0xFFFF。UTF-16的表示範圍是0到0x10FFFF,它由1個或者2個16bit的編碼單元組成。其中UCS-2是UTF-16的子集,UTF-16編碼在0到0x00FFFF的範圍稱為BMP(基本多文種平面),BMP與UCS-2的編碼完全一致。
更詳細的說明可以參考這裡。
2.1 String.fromCharCode
fromCharCode
方法返回指定的UCS-2編碼對應的字串。它是String
上的靜態方法,不可通過字串物件直接訪問。
因為入參是UCS-2編碼值,所以不能多於16bit,即入參值要小於65536。如果入參需要大於65536,可以使用 String.fromCodePoint
。
String.fromCharCode(65) // A
String.fromCharCode(65, 66, 68) // ABD
2.2 String.prototype.charCodeAt
charCodeAt
返回字串指定位置的字元的UTF-16編碼。該方法可以直接從字串物件進行呼叫。
如果該字元不能使用一個UTF-16編碼單元(16bit)來表示時,該方法只會返回第一個編碼單元。如果需要獲取完整的編碼,可以使用 String.prototype.codePointAt
。
"AB".charCodeAt(0) // 65
"AB".charCodeAt(1) // 66
3. ArrayBuffer
ArrayBuffer
用來表示原始的二進位制資料快取區,但是不可直接對ArrayBuffer
進行操作,需要藉助DataView
或者型別陣列物件來對快取區的內容進行讀寫。
3.1 DataView
DataView
可以理解為資料視窗,通過 DataView
物件可以對 ArrayBuffer
進行讀寫操作。
const buffer = new ArrayBuffer(4); // 申請2個位元組長度的快取區
const view1 = new DataView(buffer); // view1的範圍是整個快取區
const view2 = new DataView(buffer, 2, 1) // view2的範圍是從第2個位元組開始往後的一個位元組
// 向一個16bit的內容中填入一個帶符號的數
// 引數的含義依次為 輸入內容的位置、輸入的值、是否使用小端方式(預設大端)
view1.setInt16(0, 0x0A0B, false);
view1.getInt8(0); // 10,即0x0A
view1.getInt8(1); // 11,即0x0B
view2.setUint8(0, 255);
view2.getInt8(0); // 按照有符號數來讀取,結果為-1
更多的操作方法可以參考DataView。
3.2 型別陣列物件
型別陣列物件有很多種,比如Uint8Array
, Int32Array
等。將ArrayBuffer
轉化為型別陣列後,就可以像陣列一樣來操作快取區。
const buffer = new ArrayBuffer(8);
const arr1 = new Int16Array(buffer);
const arr2 = new Uint8Array(buffer);
arr1[0] = 256;
arr2[6] = 255;
console.log(arr1); // [256, 0, 0, 255]
console.log(arr2); // [0, 1, 0, 0, 0, 0, 255, 0]
參考文獻