這篇文章不講一元運算符,也就是 + 、-、 *、 /、 =、 ||、 &&、 !這些。 位運算符是在數字底層(即表示數字的32個數位)進行操作的。 有符號整數使用 32 位的前 31 位表示整數值。第 32 位表示數值的符號,如 0 表示正,1 表示負。這一位稱為符號位。 正值以真正的二進位格式存儲 ...
這篇文章不講一元運算符,也就是 + 、-、 *、 /、 =、 ||、 &&、 !這些。
位運算符是在數字底層(即表示數字的32個數位)進行操作的。
有符號整數使用 32 位的前 31 位表示整數值。第 32 位表示數值的符號,如 0 表示正,1 表示負。這一位稱為符號位。
正值以真正的二進位格式存儲,即 31位中的每一位都代表 2 的冪。第一位(稱為第 0 位)表示 2的0次冪,第二位表示 2的1次冪,依此類推。如果一個位是空的,則以0填充,相當於忽略不計。比如,數值18的二進位格式為00000000000000000000000000010010,或更精簡的 10010。後者是用到的 5 個有效位,決定了實際的值。
負值以一種稱為二補數(或補碼)的二進位編碼存儲。一個數值的二補數通過如下 3 個步驟計算得到:
(1) 確定絕對值的二進位表示(如,對於-18,先確定 18 的二進位表示);
(2) 找到數值的一補數(或反碼),換句話說,就是每個 0 都變成 1,每個 1 都變成 0;
(3) 給結果加 1。
基於上述步驟確定-18 的二進位表示,首先從 18 的二進位表示開始
0000 0000 0000 0000 0000 0000 0001 0010
然後,計算一補數,即反轉每一位的二進位值:
1111 1111 1111 1111 1111 1111 1110 1101
最後,給一補數加 1:
1111 1111 1111 1111 1111 1111 1110 1101
1
---------------------------------------
1111 1111 1111 1111 1111 1111 1110 1110
所以,-18 的二進位表示就是 11111111111111111111111111101110。
1. 按位非(~)
(~)是返回數值的一補數。
let num1 = 25; // 二進位 00000000000000000000000000011001
let num2 = ~num1; // 二進位 11111111111111111111111111100110
console.log(num2); // -26
可以看出,(~)可以當做是這個數的絕對值取反減1的二進位數;
*** 小技巧: 對一個小數兩次按位非,可以得到取整效果。
console.log(~~2.5); // 2
2. 按位與(&)
按位與操作符用和號(&)表示,有兩個操作數。本質上,按位與就是將兩個數的每一個位對齊,然後基於真值表中的規則,對每一位執行相應的與操作。
tips: 是轉化成二進位的對應位數下的值是否一致;
let result = 25 & 3;
console.log(result); // 1
25 和 3 的按位與操作的結果是 1。為什麼呢?看下麵的二進位計算過程:
25 = 0000 0000 0000 0000 0000 0000 0001 1001
3 = 0000 0000 0000 0000 0000 0000 0000 0011
---------------------------------------------
& = 0000 0000 0000 0000 0000 0000 0000 0001
如上所示,25 和 3 的二進位表示中,只有第 0 位上的兩個數都是 1。於是結果數值的所有其他位都會以 0 填充,因此結果就是 1。
*** 小技巧:和1進行按位&操作來判斷其奇偶性,比如 num&1,若為1,則num是奇數;若為0,則num是偶數。
3. 按位或(|)
按位或操作符用管道符(|)表示,同樣有兩個操作數。按位或操作在至少一位是 1 時返回 1,兩位都是 0 時返回 0。
let result = 25 | 3;
console.log(result); // 27
可見 25 和 3 的按位或操作的結果是 27:
25 = 0000 0000 0000 0000 0000 0000 0001 1001
3 = 0000 0000 0000 0000 0000 0000 0000 0011
---------------------------------------------
| = 0000 0000 0000 0000 0000 0000 0001 1011
在參與計算的兩個數中,有 4 位都是 1,因此它們直接對應到結果上。二進位碼 11011 等於 27。
4. 按位異或(^)
按位異或用脫字元(^)表示,同樣有兩個操作數。
按位異或與按位或的區別是,它只在一位上是 1 的時候返回 1(兩位都是 1 或 0,則返回 0)。
let result = 25 ^ 3;
console.log(result); // 26
可見,25 和 3 的按位異或操作結果為 26,如下所示:
25 = 0000 0000 0000 0000 0000 0000 0001 1001
3 = 0000 0000 0000 0000 0000 0000 0000 0011
---------------------------------------------
^ = 0000 0000 0000 0000 0000 0000 0001 1010
兩個數在 4 位上都是 1,但兩個數的第 0 位都是 1,因此那一位在結果中就變成了 0。其餘位上的 1
在另一個數上沒有對應的 1,因此會直接傳遞到結果中。二進位碼 11010 等於 26。
5. 左移(<<)
左移操作符用兩個小於號(<<)表示,會按照指定的位數將數值的所有位向左移動。比如,如果數值 2(二進位 10)向左移 5 位,就會得到 64(二進位 1000000)
左移會保留它所操作數值的符號。比如,如果-2 左移 5 位,將得到-64,而不是正 64。
6. 有符號右移(>>)
有符號右移由兩個大於號(>>)表示,會將數值的所有 32 位都向右移,同時保留符號(正或負)。有符號右移實際上是左移的逆運算。比如,如果將 64 右移 5 位,那就是 2。
7. 無符號右移(>>>)
無符號右移用 3 個大於號表示(>>>),會將數值的所有 32 位都向右移。
對於正數:無符號右移與有符號右移結果相同。仍然以前面有符號右移的例子為例,64 向右移動 5 位,會變成 2。
對於負數:因為負數是其絕對值的二補數,所以右移之後結果變得非常之大。
let num= -64; // 等於二進位 11111111111111111111111111000000
let result = num >>> 5; // 等於十進位 134217726
小技巧:
使用兩個嘆號(!!),相當於調用了轉型函數Boolean()。
指數操作符(**):ECMAScript 7 新增了指數操作符,Math.pow()現在有了自己的操作符**
## 雙非 !! console.log(!!"blue"); // true console.log(!!0); // false console.log(!!NaN); // false console.log(!!""); // false console.log(!!12345); // true ## 指數操作符** Math.pow(3, 2); // 3的平方: 9 3 ** 2; // 3的平方: 9 3 ** 3; // 3的三次方: 27