javascript 位元運算
1、整數的二進位碼位操作符用於在最基本的層次上,即按記憶體中表示數值的位來運算元值。ECMAScript中的所有數值都以IEEE-754 64位格式儲存,但位操作符並不直接操作64位的值。而是先將64位的值轉換成32位的整數,然後執行操作,最後再將結果轉換回64位。對於開發人員來說,由於64位儲存格式是透明的,因此整個過程就像是只存在32位的整數一樣。 對於有符號的整數,32位中的前31位用於表示整數的值。第32位用於表示數值的符號:0表示正數,1表示負數。這個表示符號的位叫做符號位。例如,數值18的二進位表示是00000000000000000000000000010010,或者更簡潔的10010。 負數同樣以二進位碼儲存,但使用的是二進位補碼(其實正數也是用補碼錶示)。計算一個數值的二進位補碼,需要經過下列三個步驟: 求這個數值絕對值的二進位碼求二進位反碼,即將0替換為1,將1替換為0得到的二進位反碼加1比如求-18的二進位碼,首先求得18的二進位碼: 0000 0000 0000 0000 0000 0001 0010然後求其二進位反碼: 1111 1111 1111 1111 1111 1110 1101最後,二進位反碼+1 1111 1111 1111 1111 1111 1110 1110這樣就求得了-18的二進位表示。 在ECMAScript中,當對數值應用位操作符時,後台會發生如下轉換過程:64位的數值被轉換成32位元值,然後執行位操作,最後再將32位的結果轉換回64位元值。這樣,表面上看起來就好像是在操作32位元值。但這個轉換過程也導致了一個嚴重的負效應,即在對特殊的NaN和Infinity值應用位操作時,這兩個值都會被當成0來處理。如果對非數值進行位操作,會先使用Number()函數將該數值轉換成一個數值(自動完成),然後再應用位操作,得到的結果是一個數值。 2、~ & | ^接下來介紹4個位操作符。 按位非操作符由一個波浪線(~)表示,執行按位非的結果就是返回數值的反碼。 var num = 25;console.log(~num); // -26對25執行按位非操作,結果得到了-26,這也驗證了之前說的結論,“一個負數的二進位碼是改數絕對值的反碼+1” 按位與操作符由一個和號字元(&)表示,它有兩個操作符數,按位與操作只在兩個數值的對應位都是1時才返回1,否則0。 按位或操作符由一個豎線符號(|)表示,同樣也有兩個操作符,在有一位是1的情況下返回1,否則0. 按位異或操作符由一個插入符號(^)表示,在兩個數值對應位上只有一個1時返回1,否則0。 3、<< >> >>>左移符號由兩個小於符號(<<)表示,這個操作符會將數值的所有位向左移動指定的位元。在左移後,原數值右側空出的位由0填補。 左移一位其實就相當於將原數值乘以2,左移不會影響運算元的符號位。 右移操作符由兩個大於符號(>>)表示,這個操作符會將數值向右移動,但保留符號位。在移位過程中,空缺位出現在原數值的左側,符號位的右側,用符號位的值來填充空位。 無符號右移操作符由三個大於符號(>>>)表示,這個操作符會將數值的所有32位都向右移動。對正數來說,無符號右移的結果和有符號相同,但是對負數來說就不一樣了,無符號右移會把負數的符號位也進行移動,左邊空出位置用0填充。 var num = -64;console.log(num >> 5); // -2console.log(num >>> 5); // 134217726 對-64進行無符號右移操作,將其用二進位碼錶示: 1111 1111 1111 1111 1111 1111 1100 0000右移5位後: 0000 0111 1111 1111 1111 1111 1111 1110即十進位的134217726。 notice:並沒有無符號左移! 4、關於位元運算的坑瞭解的基本的位元運算操作後,這裡我要談談我經常碰到的一個坑。 int32的取值範圍是-2^31 ~ 2^31-1,於是我經常會去求1<<31的值,但是是溢出的... console.log(1 << 31); // -2147483648 原因很簡單,1的左邊只有30位可以移動,實際上把1移到了符號位上,得到了: 1000 0000 0000 0000 0000 0000 0000 0000所以要求2的31次方可以這樣: console.log(Math.pow(2, 31)); // 2147483648 console.log(2 * (1 << 30)); // 21474836482的31次方減1也可以這樣表示: ~(1 << 31)so int32能表示的數的範圍是:1 << 31 - ~(1 << 31)