聊聊JavaScript中的7種位運運算元,看看在實戰中如何妙用?

2022-01-06 13:00:48
本篇文章帶大家瞭解一下JavaScript中的7種位運運算元,看看如何妙用這7種位運運算元,希望對大家有所幫助!

位運運算元

操作符用於數值的底層操作,也就是操作記憶體中表示資料的位元(位)。

ECMAScript 中的所有數值都以 IEEE 754 64 位格式儲存,但位元運算並不直接應用到 64 位表示,而是先把值轉換為 32 位整數,再進行位元運算,之後再把結果轉換為 64 位。

對開發者而言,就好像只有 32 位整數一樣,因 為 64 位整數儲存格式是不可見的。既然知道了這些,就只需要考慮 32 位整數即可。

有符號整數使用 32 位的前 31 位表示整數值。第 32 位表示數值的符號,如 0 表示正,1 表示負。這 一位稱為符號位(sign bit),它的值決定了數值其餘部分的格式。正值以真正的二進位制格式儲存,即 31 位中的每一位都代表 2 的冪。第一位(稱為第 0 位)表示 20 ,第二位表示 21 ,依此類推。

如果一個位是空的,則以0填充,相當於忽略不計。比如,數值18的二進位制格式為00000000000000000000000000010010, 或更精簡的 10010。後者是用到的 5 個有效位,決定了實際的值(如下圖所示)。

1.png

按位元非

按位元非操作符用波浪符(~)表示,它的作用是返回數值的一補數。按位元非是 ECMAScript 中為數 不多的幾個二進位制數學操作符之一。看下面的例子:

let num1 = 25; //二進位制 00000000000000000000000000011001
let num2 = ~num1; // 二進位制 11111111111111111111111111100110
console.log(num2); // -26

這裡,按位元非操作符作用到了數值 25,得到的結果是26。由此可以看出,按位元非的最終效果是對 數值取反並減 1,就像執行如下操作的結果一樣:

let num1 = 25;
let num2 = -num1 - 1;
console.log(num2); // "-26"

實際上,儘管兩者返回的結果一樣,但位元運算的速度快得多。這是因為位元運算是在數值的底層表示 上完成的。

按位元與 &

按位元與操作符用和號(&)表示,有兩個運算元。本質上,按位元與就是將兩個數的每一個位對齊, 然後基於真值表中的規則,對每一位執行相應的與操作。

2.png

按位元與操作在兩個位都是 1 時返回 1,在任何一位是 0 時返回 0。 下面看一個例子,我們對數值 25 和 3 求與操作,如下所示:

let result = 25 & 3;
console.log(result); // 1 25 和 3 的按位元與操作的結果是 1。

為什麼呢?看下面的二進位制計算過程:

3.png

如上圖所示,25 和 3 的二進位制表示中,只有第 0 位上的兩個數都是 1。於是結果數值的所有其他位都 會以 0 填充,因此結果就是 1。

按位元或

按位元或操作符用管道符(|)表示,同樣有兩個運算元。按位元或遵循如下真值表:

4.png

按位元或操作在至少一位是 1 時返回 1,兩位都是 0 時返回 0。 仍然用按位元與的範例,如果對 25 和 3 執行按位元或,程式碼如下所示:

let result = 25 | 3;
console.log(result); // 27

可見 25 和 3 的按位元或操作的結果是 27:

5.png

在參與計算的兩個數中,有 4 位都是 1,因此它們直接對應到結果上。二進位制碼 11011 等於 27。

按位元互斥或 ^

按位元互斥或用脫字元(^)表示,同樣有兩個運算元。下面是按位元互斥或的真值表:

6.png

按位元互斥或與按位元或的區別是,它只在一位上是 1 的時候返回 1(兩位都是 1 或 0,則返回 0)。 對數值 25 和 3 執行按位元互斥或操作:

let result = 25 ^ 3;
console.log(result); // 26

可見,25 和 3 的按位元互斥或操作結果為 26,如下所示:

7.png

兩個數在 4 位上都是 1,但兩個數的第 0 位都是 1,因此那一位在結果中就變成了 0。其餘位上的 1 在另一個數上沒有對應的 1,因此會直接傳遞到結果中。二進位制碼 11010 等於 26。(注意,這比對同樣 兩個值執行按位元或操作得到的結果小 1。)

左移 <<

左移操作符用兩個小於號(<<)表示,會按照指定的位數將數值的所有位向左移動。比如,如果數 值 2(二進位制 10)向左移 5 位,就會得到 64(二進位制 1000000),如下所示:

let oldValue = 2; // 等於二進位制 10
let newValue = oldValue << 5; // 等於二進位制 1000000,即十進位制 64

注意在移位後,數值右端會空出 5 位。左移會以 0 填充這些空位,讓結果是完整的 32 位數值(見下圖)。

8.png

注意,左移會保留它所運算元值的符號。比如,如果-2 左移 5 位,將得到-64,而不是正 64。

有符號右移 >>

有符號右移由兩個大於號(>>)表示,會將數值的所有 32 位都向右移,同時保留符號(正或負)。 有符號右移實際上是左移的逆運算。比如,如果將 64 右移 5 位,那就是 2:

let oldValue = 64; // 等於二進位制 1000000
let newValue = oldValue >> 5; // 等於二進位制 10,即十進位制 2

同樣,移位後就會出現空位。不過,右移後空位會出現在左側,且在符號位之後(見圖 3-3)。 ECMAScript 會用符號位的值來填充這些空位,以得到完整的數值。

9.png

無符號右移 >>>

無符號右移用 3 個大於號表示(>>>),會將數值的所有 32 位都向右移。對於正數,無符號右移與 有符號右移結果相同。仍然以前面有符號右移的例子為例,64 向右移動 5 位,會變成 2:

let oldValue = 64; // 等於二進位制 1000000 
let newValue = oldValue >>> 5; // 等於二進位制 10,即十進位制 2

對於負數,有時候差異會非常大。與有符號右移不同,無符號右移會給空位補 0,而不管符號位是 什麼。對正數來說,這跟有符號右移效果相同。但對負數來說,結果就差太多了。無符號右移操作符將負數的二進位制表示當成正數的二進位制表示來處理。因為負數是其絕對值的二補數,所以右移之後結果變 得非常之大,如下面的例子所示:

let oldValue = -64; // 等於二進位制 11111111111111111111111111000000
let newValue = oldValue >>> 5; // 等於十進位制 134217726

在對-64 無符號右移 5 位後,結果是 134 217 726。這是因為-64 的二進位制表示是 1111111111111111111 1111111000000,無符號右移卻將它當成正值,也就是 4 294 967 232。把這個值右移 5 位後,結果是 00000111111111111111111111111110,即 134 217 726。

實戰中的妙用

1.判斷奇偶數

// 偶數 & 1 = 0
// 奇數 & 1 = 1
console.log(2 & 1) // 0
console.log(3 & 1) // 1

2. 使用^來完成值的交換

let a = 2
let b = 5
a ^= b
b ^= a
a ^= b
console.log(a) // 5
console.log(b) // 2

3. 使用~進行判斷

// 常用判斷
if (arr.indexOf(item) > -1) {
    // code
}
// 按位元非    ~-1 = -(-1) - 1 取反再 -1
if (~arr.indexOf(item)) {
    // code
}

4. 使用&>>|來完成rgb值和16進位制顏色值之間的轉換

/**
 * 16進位制顏色值轉RGB
 * @param  {String} hex 16進位制顏色字串
 * @return {String}     RGB顏色字串
 */
  function hexToRGB(hex) {
    var hexx = hex.replace('#', '0x')
    var r = hexx >> 16
    var g = hexx >> 8 & 0xff
    var b = hexx & 0xff
    return `rgb(${r}, ${g}, ${b})`
}

/**
 * RGB顏色轉16進位制顏色
 * @param  {String} rgb RGB進位制顏色字串
 * @return {String}     16進位制顏色字串
 */
function RGBToHex(rgb) {
    var rgbArr = rgb.split(/[^\d]+/)
    var color = rgbArr[1]<<16 | rgbArr[2]<<8 | rgbArr[3]
    return '#'+ color.toString(16)
}
// -------------------------------------------------
hexToRGB('#ffffff')               // 'rgb(255,255,255)'
RGBToHex('rgb(255,255,255)')      // '#ffffff'

5. 使用|~>><<>>>來取整

console.log(~~ 3.1415)    // 3
console.log(3.1415 >> 0)  // 3
console.log(3.1415 << 0)  // 3
console.log(3.1415 | 0)   // 3
// >>>不可對負數取整
console.log(3.1415 >>> 0)   // 3

【相關推薦:

以上就是聊聊JavaScript中的7種位運運算元,看看在實戰中如何妙用?的詳細內容,更多請關注TW511.COM其它相關文章!