js位運算符

我們可能很少在編程中用位運算,如果沒深入學習,可能也很難理解。平時的數值運算,其實是要先轉換成二進制再進行運算的,而位運算就是直接進行二進制運算,所以位運算的執行效率肯定是更高的。下面通過一些實例來加深對位運算的理解。

按位與(&)

&&運算符我們都知道,只有兩個都爲真,結果才爲真。&道理是一樣的,只有兩個數的值爲1時,才返回1。例如1和3的按位與操作:

                    0001
                 &  0011
                ---------
                    0001

只有對應的數爲1時,結果才爲1,其他都爲0。
判斷一個數是奇數還是偶數,我們會用求餘數來判斷:

function assert(n) {
        if (n % 2 === 1) {
    console.log("n是奇數");
    } else {
    console.log("n是偶數");
   }
}

assert(3); // "n是奇數"

我們也可以用一個數和1進行按位&操作來判斷,而且速度更快:

function assert(n) {
if (n & 1) {
    console.log("n是奇數");
} else {
    console.log("n是偶數");
}
}

assert(3); // "n是奇數"

下面是位運算過程:

                 1 = 0001
                 3 = 0011
                 --------
                     & = 0001

奇數的二進制碼的最後一位數肯定是1,而1只有最後一位爲1,按位&操作之後,結果肯定只有最後一位數爲1。而偶數的二進制表示的最後一位數是0,和1進行按位&操作,結果所有位數都爲0。

按位或(|)

|與||操作符的道理也是一樣的,只要兩個數中有一個數爲1,結果就爲1,其他則爲0。

                        0001
                 |  0011
                ---------
                    0011

對浮點數向下求整,我們會用下面的方法:

var num = Math.floor(1.1); // 1

我們也可以用位運算來求整:

var num = 1.1 | 0; // 1

其實浮點數是不支持位運算的,所以會先把1.1轉成整數1再進行位運算,就好像是對浮點數向下求整。所以1|0的結果就是1。

按位非(~)

按位非就是求二進制的反碼:

var num = 1; // 二進制 00000000000000000000000000000001
var num1 = ~num; // 二進制 11111111111111111111111111111110

我們知道,js中的數字默認是有符號的。有符號的32位二進制的最高位也就是第一位數字代表着正負,1代表負數,0代表整數。那到底11111111111111111111111111111110等於多少呢?最高位爲1代表負數,負數的二進制轉化爲十進制:符號位不變,其他位取反加1。取反之後爲10000000000000000000000000000001,加1之後爲10000000000000000000000000000010,十進制爲-2。

按位異或(^)

按位異或是兩個數中只有一個1時返回1,其他情況返回0。(相同時返回0,不同時返回1)

                        0001
                 ^  0011
                ---------
                    0010

數字與數字本身按位異或操作得到的是0,因爲每兩個對應的數字都相同,所以最後返回的都是0。

我們經常會需要調換兩個數字的值:

var num1 = 1, num2 = 2, temp;
temp = num1;
num1 = num2; // 2
num2 = temp; // 1

如果裝逼一點的話,可以這樣:

var num1 = 1, num2 = 2;
num1 = [num2, num2 = num1][0];
console.log(num1); // 2
console.log(num2); // 1

如果想再裝的穩一點的話,可以這樣:

var num1 = 1, num2 = 2;
num1 ^= num2; // num1 = num1 ^ num2 = 1 ^ 2 = 3
num2 ^= num1; // num2 = num2 ^ (num1 ^ num2) = 2 ^ (1 ^ 2) = 1
num1 ^= num2; // num1 = num1 ^ num2 = 3 ^ 1 = 2
console.log(num1); // 2
console.log(num2); // 1

有符號左移(<<)

有符號左移會將32位二進制數的所有位向左移動指定位數。如:

var num = 2; // 二進制10
num = num << 5; // 二進制1000000,十進制64

如果要求2的n次方,可以這樣:

function power(n) {
    return 1 << n;
}

power(5); // 32

1的二進制是01,左移5位就是0100000,十進制就是2的5次方32。

有符號右移(>>)

有符號右移會將32位二進制數的所有位向右移動指定位數。如:

var num = 64; // 二進制1000000
num = num >> 5; // 二進制10,十進制2

求一個數的二分之一:

var num = 64 >> 1; // 32

有符號左移與右移不會影響符號位。

無符號右移(>>>)

正數的無符號右移與有符號右移結果是一樣的。負數的無符號右移會把符號位也一起移動,而且無符號右移會把負數的二進制碼當成正數的二進制碼:

(result = expression1 >>> expression2

其中result是任何變量。 
expression1是任何表達式。 
expression2是任何表達式。

>>> 運算符把 expression1 的各個位向右移 expression2 指定的位數。右移後左邊空出的位用零來填充。移出右邊的位被丟棄)

var num = -64; // 11111111111111111111111111000000
num = num >>> 5; // 134217726

所以,我們可以利用無符號右移來判斷一個數的正負:

function isPos(n) {
return (n === (n >>> 0)) ? true : false;    
}

isPos(-1); // false
isPos(1); // true

-1>>>0雖然沒有向右移動位數,但-1的二進制碼已經變成了正數的二進制碼:

11111111111111111111111111111111 

所以-1>>>0的值爲4294967295。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章