--- title: 位元運算子 slug: Web/JavaScript/Reference/Operators/Bitwise_Operators translation_of: Web/JavaScript/Reference/Operators translation_of_original: Web/JavaScript/Reference/Operators/Bitwise_Operators ---
位元運算子將運算元視為一段 32 位元長的 0 和 1 序列,而不是十進位、十六進位或八進位的 Numbers
。 舉例來說,十進位的 9 可以用二進位表示為 1001。位元運算子對這樣的二進位表示法進行運算,然後回傳標準 JavaScript 數值。
下表總結了 JavaScript 的位元運算子:
Operator | Usage | Description |
---|---|---|
位元 AND | a & b |
當兩運算元的該位置皆為 1 時,回傳值的該位置為 1 。 |
位元 OR | a | b |
當兩運算元的該位置有一者為 1 時,回傳值的該位置為 1 。 |
位元 XOR | a ^ b |
當兩運算元的該位置恰好一者為 1 時,回傳值的該位置為 1 。 |
位元 NOT | ~ a |
將運算元的所有位元反轉。 |
左移 | a << b |
將 a 的二進位表示法左移 b (< 32) 位元,右側補 0 。 |
保持符號右移 | a >> b |
將 a 的二進位表示法右移 b (< 32) 位元,拋棄被移出的位元。 |
填零右移 | a >>> b |
將 a 的二進位表示法右移 b (< 32) 位元,拋棄被移出的位元,並於右側補 0 。 |
所有位元運算子的運算元皆會被轉換成二補數系統下的帶號32位元整數。二補數系統意味著一個整數的加法反元素(例如 5和 -5)是該整數的所有位元反轉(位元 NOT,也就是該數的一補數) 再加一。舉例來說,下面的序列代表著整數 314:
00000000000000000000000100111010
下面的序列代表 ~314
,也就是 314
的一補數:
11111111111111111111111011000101
接著,下面代表著 -314
,也就是 314
的二補數:
11111111111111111111111011000110
二補數系統確保了正值時最左邊的位元為 0,反之則為 1。因此,最左邊的位元被稱作符號位。
整數 0
全由位元 0組成。
0 (base 10) = 00000000000000000000000000000000 (base 2)
整數 -1
全由位元 1組成。
-1 (base 10) = 11111111111111111111111111111111 (base 2)
整數 -2147483648
(十六進位: -0x80000000
) 除了第一位為 1,其餘皆由位元 0組成。
-2147483648 (base 10) = 10000000000000000000000000000000 (base 2)
整數 -2147483648
(十六進位: -0x7fffffff
) 除了第一位為 0,其餘皆由位元 1組成。
2147483647 (base 10) = 01111111111111111111111111111111 (base 2)
整數 -2147483648
和 2147483647
分別為帶號32位元整數所能表示的最小值和最大值。
大致上,位元邏輯運算子的運作如下︰
Before: 11100110111110100000000000000110000000000001 After: 10100000000000000110000000000001
對每一組位元執行 AND 運算。a
AND b
只在 a
和 b
同時為 1
時得到 1。AND運算的真值表如下:
a | b | a AND b |
0 | 0 | 0 |
0 | 1 | 0 |
1 | 0 | 0 |
1 | 1 | 1 |
. 9 (base 10) = 00000000000000000000000000001001 (base 2) 14 (base 10) = 00000000000000000000000000001110 (base 2) -------------------------------- 14 & 9 (base 10) = 00000000000000000000000000001000 (base 2) = 8 (base 10)
將任何數 x
和 0
做位元 AND 皆會得到 0
。將任何數 x
和 -1 做位元 AND 皆會得到 x。
對每一組位元執行 OR 運算。a
OR b
在 a
和 b
有一者為 1
時得到 1。OR運算的真值表如下:
a | b | a OR b |
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 1 |
. 9 (base 10) = 00000000000000000000000000001001 (base 2) 14 (base 10) = 00000000000000000000000000001110 (base 2) -------------------------------- 14 | 9 (base 10) = 00000000000000000000000000001111 (base 2) = 15 (base 10)
將任何數 x
和 0
做位元 OR 皆會得到 x。將任何數 x
和 -1 做位元 OR 皆會得到 -1。
對每一組位元執行 XOR 運算。a
XOR b
只在 a
和 b
恰一者為 1
時得到 1。XOR運算的真值表如下:
a | b | a XOR b |
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 0 |
. 9 (base 10) = 00000000000000000000000000001001 (base 2) 14 (base 10) = 00000000000000000000000000001110 (base 2) -------------------------------- 14 ^ 9 (base 10) = 00000000000000000000000000000111 (base 2) = 7 (base 10)
將任何數 x
和 0
做位元 AND 皆會得到 x。將任何數 x
和 -1 做位元 AND 皆會得到 ~x
。
對每一個位元執行 NOT 運算。NOT a
會得到 a
的反轉值(也就是一補數)。NOT運算的真值表如下:
a | NOT a |
0 | 1 |
1 | 0 |
9 (base 10) = 00000000000000000000000000001001 (base 2) -------------------------------- ~9 (base 10) = 11111111111111111111111111110110 (base 2) = -10 (base 10)
將任何數 x
做位元 NOT 皆會得到 -(x + 1)
。舉例來說,~-5
會得到 4
。
值得注意的是,因為使用 32位元表示法表示數值 ~-1
和 ~4294967295
(232-1) 皆會得到 0
。
位移運算子需要兩個運算元:第一個是要被位移的值,第二個是位元位移量。位移的方向取決於使用的運算子。
位移運算子將運算元轉換成 32位元的大端序整數並回傳一個與左運算元相同類別的值。右運算元應不大於32,如果超過的話,將只會使用後 5個位元。
將第一個運算元向左位移指定的量。被移出的位元會被拋棄,並從右側補零。
例如,9 << 2
會得到 36:
. 9 (base 10): 00000000000000000000000000001001 (base 2) -------------------------------- 9 << 2 (base 10): 00000000000000000000000000100100 (base 2) = 36 (base 10)
將任意值 x
左移 y
位元會得到 x * 2 ** y
。
將第一個運算元向右位移指定的量。被移出的位元會被拋棄,並從左側補進和原本最左端相同的位元值。因為新的最左端位元和原本的最左端位元是一樣的,符號位(最左端位元)並不會改變。「保持符號」之名便是因此。
例如,9 >> 2
會得到 2:
. 9 (base 10): 00000000000000000000000000001001 (base 2) -------------------------------- 9 >> 2 (base 10): 00000000000000000000000000000010 (base 2) = 2 (base 10)
同樣地,-9 >> 2
會得到 -3
,因為符號會保持不變。
. -9 (base 10): 11111111111111111111111111110111 (base 2) -------------------------------- -9 >> 2 (base 10): 11111111111111111111111111111101 (base 2) = -3 (base 10)
將第一個運算元向右位移指定的量。被移出的位元會被拋棄,並從左側補零。因為符號位變成 0,所以結果永遠都是正值。
對非負的數來說,填零右移會得到和保持符號右移一樣的結果。例如,9 >>> 2
和 9 >> 2
一樣,皆會得到 2:
. 9 (base 10): 00000000000000000000000000001001 (base 2) -------------------------------- 9 >>> 2 (base 10): 00000000000000000000000000000010 (base 2) = 2 (base 10)
然而對負值來說並不是這麼一回事。例如,-9 >>> 2
會得到 1073741821,跟 -9 >> 2
(得到 -3
)的結果是不一樣的:
. -9 (base 10): 11111111111111111111111111110111 (base 2) -------------------------------- -9 >>> 2 (base 10): 00111111111111111111111111111101 (base 2) = 1073741821 (base 10)
位元運算子常被用於生成、修改、和讀取旗標序列,就像是二進制的變數一般。雖然也可以使用普通變數,但使用二進制的旗標序列大大的減少了所需空間 (32 倍)。
假設有 4個旗標:
這些旗標倍表達成一個位元序列:DCBA。當一個旗標被立起 (set)時,其值為1。當一個旗標被放下 (clear),其值為0。假設有一變數 flags
的二進位值為 0101:
var flags = 5; // 二進位 0101
這個值表示:
因為位元運算子進行的是 32位元操作,0101 實際上是 00000000000000000000000000000101,但前導的 0可被忽略因為他們沒有實際上的意義。
位元遮罩則為一個可以修改且(或)讀取旗標序列的位元序列。通常為每個單獨旗標為真的「初始」值:
var FLAG_A = 1; // 0001 var FLAG_B = 2; // 0010 var FLAG_C = 4; // 0100 var FLAG_D = 8; // 1000
新的位元遮罩可以透過對初始遮罩進行位元運算獲得。例如,遮罩 1011 可以透過對 FLAG_A、FLAG_B、和 FLAG_D進行 OR運算獲得:
var mask = FLAG_A | FLAG_B | FLAG_D; // 0001 | 0010 | 1000 => 1011
Individual flag values can be extracted by ANDing them with a bitmask, where each bit with the value of one will "extract" the corresponding flag. The bitmask masks out the non-relevant flags by ANDing with zeroes (hence the term "bitmask"). For example, the bitmask 0100 can be used to see if flag C is set:
// if we own a cat if (flags & FLAG_C) { // 0101 & 0100 => 0100 => true // do stuff }
A bitmask with multiple set flags acts like an "either/or". For example, the following two are equivalent:
// if we own a bat or we own a cat // (0101 & 0010) || (0101 & 0100) => 0000 || 0100 => true if ((flags & FLAG_B) || (flags & FLAG_C)) { // do stuff }
// if we own a bat or cat var mask = FLAG_B | FLAG_C; // 0010 | 0100 => 0110 if (flags & mask) { // 0101 & 0110 => 0100 => true // do stuff }
Flags can be set by ORing them with a bitmask, where each bit with the value one will set the corresponding flag, if that flag isn't already set. For example, the bitmask 1100 can be used to set flags C and D:
// yes, we own a cat and a duck var mask = FLAG_C | FLAG_D; // 0100 | 1000 => 1100 flags |= mask; // 0101 | 1100 => 1101
Flags can be cleared by ANDing them with a bitmask, where each bit with the value zero will clear the corresponding flag, if it isn't already cleared. This bitmask can be created by NOTing primitive bitmasks. For example, the bitmask 1010 can be used to clear flags A and C:
// no, we don't have an ant problem or own a cat var mask = ~(FLAG_A | FLAG_C); // ~0101 => 1010 flags &= mask; // 1101 & 1010 => 1000
The mask could also have been created with ~FLAG_A & ~FLAG_C
(De Morgan's law):
// no, we don't have an ant problem, and we don't own a cat var mask = ~FLAG_A & ~FLAG_C; flags &= mask; // 1101 & 1010 => 1000
Flags can be toggled by XORing them with a bitmask, where each bit with the value one will toggle the corresponding flag. For example, the bitmask 0110 can be used to toggle flags B and C:
// if we didn't have a bat, we have one now, // and if we did have one, bye-bye bat // same thing for cats var mask = FLAG_B | FLAG_C; flags = flags ^ mask; // 1100 ^ 0110 => 1010
Finally, the flags can all be flipped with the NOT operator:
// entering parallel universe... flags = ~flags; // ~1010 => 0101
Convert a binary String
to a decimal Number
:
var sBinString = '1011'; var nMyNumber = parseInt(sBinString, 2); alert(nMyNumber); // prints 11, i.e. 1011
Convert a decimal Number
to a binary String
:
var nMyNumber = 11; var sBinString = nMyNumber.toString(2); alert(sBinString); // prints 1011, i.e. 11
You can create multiple masks from a set of Boolean
values, like this:
function createMask() { var nMask = 0, nFlag = 0, nLen = arguments.length > 32 ? 32 : arguments.length; for (nFlag; nFlag < nLen; nMask |= arguments[nFlag] << nFlag++); return nMask; } var mask1 = createMask(true, true, false, true); // 11, i.e.: 1011 var mask2 = createMask(false, false, true); // 4, i.e.: 0100 var mask3 = createMask(true); // 1, i.e.: 0001 // etc. alert(mask1); // prints 11, i.e.: 1011
If you want to create an Array
of Booleans
from a mask you can use this code:
function arrayFromMask(nMask) { // nMask must be between -2147483648 and 2147483647 if (nMask > 0x7fffffff || nMask < -0x80000000) { throw new TypeError('arrayFromMask - out of range'); } for (var nShifted = nMask, aFromMask = []; nShifted; aFromMask.push(Boolean(nShifted & 1)), nShifted >>>= 1); return aFromMask; } var array1 = arrayFromMask(11); var array2 = arrayFromMask(4); var array3 = arrayFromMask(1); alert('[' + array1.join(', ') + ']'); // prints "[true, true, false, true]", i.e.: 11, i.e.: 1011
You can test both algorithms at the same time…
var nTest = 19; // our custom mask var nResult = createMask.apply(this, arrayFromMask(nTest)); alert(nResult); // 19
For the didactic purpose only (since there is the Number.toString(2)
method), we show how it is possible to modify the arrayFromMask
algorithm in order to create a String
containing the binary representation of a Number
, rather than an Array
of Booleans
:
function createBinaryString(nMask) { // nMask must be between -2147483648 and 2147483647 for (var nFlag = 0, nShifted = nMask, sMask = ''; nFlag < 32; nFlag++, sMask += String(nShifted >>> 31), nShifted <<= 1); return sMask; } var string1 = createBinaryString(11); var string2 = createBinaryString(4); var string3 = createBinaryString(1); alert(string1); // prints 00000000000000000000000000001011, i.e. 11
Specification | Status | Comment |
---|---|---|
{{SpecName('ES1')}} | {{Spec2('ES1')}} | Initial definition. |
{{SpecName('ES5.1', '#sec-11.7')}} | {{Spec2('ES5.1')}} | Defined in several sections of the specification: Bitwise NOT operator, Bitwise shift operators, Binary bitwise operators |
{{SpecName('ES6', '#sec-bitwise-shift-operators')}} | {{Spec2('ES6')}} | Defined in several sections of the specification: Bitwise NOT operator, Bitwise shift operators, Binary bitwise operators |
{{SpecName('ESDraft', '#sec-bitwise-shift-operators')}} | {{Spec2('ESDraft')}} | Defined in several sections of the specification: Bitwise NOT operator, Bitwise shift operators, Binary bitwise operators |
The compatibility table on this page is generated from structured data. If you'd like to contribute to the data, please check out https://github.com/mdn/browser-compat-data and send us a pull request.
{{Compat("javascript.operators.bitwise")}}