討論邏輯運算子(logical operators)與位元運算子(bitwise operators)的使用情境
Part I. logical operators
Part II. bitwise operators (1)
Part II. bitwise operators (2)
Part II. bitwise operators (3)
在開始討論 bitwise operators 之前,這邊補充一下 logical operators 的 ! not。
要如何判斷一個 js 的物件是 undefined 或 null?
通常可以這樣寫:
return !(typeof value === "undefined" || value === null);
// 可以換成 double not 的寫法:
return !!value;
第二種寫法精簡很多,缺點是比較看不出你不要的是什麼,也要留意 js 中對 false 的判斷。跟 || 與 && 的討論一樣,要看懂 !! 必須要回到 ! 的定義:
Returns false if its single operand can be converted to true; otherwise, returns true.
也就是當 !expr 中的 expr 是 false 的時候,就回傳 true。而 js 中 false, null, undefined, 空字串'', 數值 0 與數值 NaN 會被視為 false。所以當 value 為 null 或 undefined 的時候,會被當成 false,!value就會是 true,再加上一個 !(!value),又會再變成 false,這也就是第一種寫法中,我們想要得到的結果。
******************************************
補充完畢,回到這邊的重點 bitwise operatros。
位元運算子的長相跟邏輯運算子太像了,意義上也是有相關聯,一般書上幾乎都是帶過而已,不過在我過去的程式開發經驗上,能用得上的話,會挺方便的。
&& 與 || 等邏輯運算子是用來作邏輯判斷的,而 bitwise operators既然是叫bit,表示他是在做位元間的運算的,人工要進行位元運算的話,必須要先把數字轉換成 2 進位的樣子,例如 10 進位的 9 換成 2 進位就是 1001,轉換的方式可以用小算盤,js 的話可以利用 toString(2)來轉換。
var number = 9;
var result = number.toString(2); // result 為 1001
我們用js進行位元運算時,並不需要先轉成 2 進位的表示方式,但心裡要知道,它底下就是那樣運作的。
bitwise operators 包括 &(AND), |(OR), ^(XOR), ~(NOT), <<(左移), >>(右移), >>>(右移填0)。
其定義分別為:
bit1 & bit2 : 當兩個位元都是1時,回傳1。
bit1 | bit2 : 其中一個位元是1時,回傳1。
bit1 ^ bit2 : 當兩個位元一樣時回傳0,不一樣時回傳1。
~bit : 當bit是1的時候回傳0,bit是0的時候回傳1。
(位移的部分之後以實例來討論再討論。)
9 (base 10) = 1001 (base 2)
15 (base 10) = 1111 (base 2)
這邊可以發現,一個數字跟全是 1 的做 AND 會是自己,跟全是 1 的作 OR 會是全是 1 的那個數字;大家也可以試試看跟全是 0 的數字(其實就是 0 )做 AND 跟 OR 會發生什麼事。
結論就是一個數字跟全是 0 的做 AND 會是 0,跟全是 0 的作 OR 會是全是自己。
這些特性在後面操作的時候,會有很大的用處。
那 >> 右移跟 << 左移又是什麼呢?
bits >> num : 右移,又稱為有正負號的右移,會把 bits 往右移動 num 位置,num 介於 0 ~ 31 之間,左邊則補上原本的bits數字的正負號。
num 是介於 0 ~ 31 之間是因為通常我們會把數字寫成 32位元的二進位表示法。
例如 9 = 00001001 (base 2) 這邊只寫出8位,而 9 是正數,正負號位元為 0,所以會是補 0。
9 >> 1 = 00000100 原本最右邊的 1 會移掉(移掉 1 個),左邊補上 0。
9 >> 2 = 00000010 原本最右邊的 01 會移掉(移掉 2 個),左邊補上 0。
負數的部分等之後講解負數的位元組再另外舉例。
bits >>> num : 補 0 的右移,跟 >> 的操作一樣,只是不管數字原本的正負,左邊一律補 0。
bits << num : 左移,又稱為有正負號的右移,會把 bits 往左移動 num 位置,num 介於 0 ~ 31 之間,右邊則補上 0。
例如 9 = 00001001 (base 2) (這邊只寫出8位)
9 << 1 = 00010010 往左移 1 位,右邊補上 0
9 << 2 = 00100100 往左移 2 位,右邊補上 0
再仔細觀察一下:
8 = 00001000
8 >> 1 = 00000100 = 4 --> 其實是 8 除 2 的結果
8 << 1 = 00010000 = 16 --> 其實是 8 乘 2 的結果
9 = 00001001
9 >> 1 = 00000100 = 4 --> 其實是 9 除 2 取整數的結果
9 << 1 = 00010010 = 18 --> 其實是 9 乘 2 的結果
以上,基本操作大致講解完畢,接下來會舉兩個例子給大家看一下。
註:bitwise 在 Javascript: The Good Parts 中被歸在不良的部分,把理由寫給大家看看,大家參考一下,就算在 JS 中不被建議使用,同樣的技巧也是可以用在其他程式語言,大家可以學習一下這樣的概念。
在多數的語言中,位元運算子離硬體很近,速度非常快速,但在 JS 中,位元運算子與硬體的距離很遠,而且非常緩慢,又容易與邏輯運算子混淆,因此不建議使用。
from Javascript: The Good Parts 中文版 119頁