AND/OR/XOR/NOT and Shifts All Coerce Operands to Signed 32-Bit Integers
Bitwise Operators and int32 Coercion
JavaScript's bitwise operators silently convert their operands to signed 32-bit integers, which enables fast tricks like flooring with |0 but produces surprising results for large numbers — BigInt is the safe escape hatch.
What you'll learn
- Apply AND, OR, XOR, NOT, and shift operators to solve common bit problems
- Explain why JS bitwise ops coerce to int32 and the implications for values above 2^31
- Use BigInt bitwise operators for integers that exceed the 32-bit range
JavaScript numbers are 64-bit IEEE 754 floats, but every bitwise operator
(&, |, ^, ~, <<, >>, >>>) first converts both operands to a
signed 32-bit integer, performs the operation in 32-bit space, then returns
the result as a regular JS number. This is fast and enables some clever tricks
— but it silently truncates values outside the range -2,147,483,648 to
2,147,483,647.
The Six Operators
| Operator | Name | Effect on bits |
|---|---|---|
a & b | AND | 1 only where both are 1 |
a | b | OR | 1 where either is 1 |
a ^ b | XOR | 1 where bits differ |
~a | NOT | flip all bits (equals -(a+1)) |
a << n | Left shift | multiply by 2^n (mod 32) |
a >> n | Right shift | divide by 2^n, preserve sign |
a >>> n | Unsigned right shift | divide by 2^n, fill with 0 |
console.log(5 & 3); // 1 (0101 & 0011 = 0001)
console.log(5 | 3); // 7 (0101 | 0011 = 0111)
console.log(5 ^ 3); // 6 (0101 ^ 0011 = 0110)
console.log(~5); // -6 (flip bits of 0…0101 => 1…1010, two's complement = -6)
console.log(1 << 4); // 16
console.log(16 >> 2); // 4 The int32 Coercion Gotcha
// x | 0 is a popular floor-to-integer trick
console.log(3.9 | 0); // 3 — works fine
console.log(2 ** 31 | 0); // -2147483648 — overflows to most negative int32!
console.log(2 ** 32 + 1 | 0); // 1 — upper 32 bits are discarded Any value whose absolute value exceeds 2^31 - 1 will be silently mangled by a bitwise op. If you need to bit-manipulate large integers, use BigInt.
BigInt Bitwise Operations
BigInt literals end with n. All bitwise operators work on BigInt operands, but
you cannot mix BigInt and Number in the same expression.
const big = 2n ** 40n; // 1099511627776n
console.log(big & 0xFFn); // 0n — low 8 bits of a 40-bit number
console.log(big | 1n); // 1099511627777n — set bit 0
console.log(big >> 8n); // 4294967296n (shift amount must also be BigInt) Note that >>> (unsigned right shift) is not defined for BigInt — it would
be meaningless because BigInt has arbitrary precision and no fixed sign bit.
Common Tricks
// Fast integer floor (safe only for |x| < 2^31)
const floor = x => x | 0;
// Swap without a temp variable
let a = 7, b = 3;
a ^= b; b ^= a; a ^= b;
console.log(a, b); // 3 7
// Check if n is a power of two
const isPow2 = n => n > 0 && (n & (n - 1)) === 0;
console.log(isPow2(64)); // true
console.log(isPow2(100)); // false Up Next
Build on these fundamentals to set, clear, toggle, and test individual bits using bit masks.
Bit Masks →