Bit Manipulation
Bitwise operators read and change the individual binary digits of a number directly, which is often far faster than arithmetic on the whole value.
Loading visual…
Definition
Every number is stored as a sequence of binary digits, or bits, and bitwise operators act on those bits directly instead of treating the number as a single arithmetic value. AND (&) keeps only the bits that are 1 in both operands, OR (|) keeps a bit that is 1 in either operand, and XOR (^) keeps a bit that is 1 in exactly one of the two operands, so XORing a value with itself always clears every bit to 0, and XORing a value with 0 leaves it unchanged. The shift operators move bits left or right: x << 1 shifts every bit one place left, which doubles x, and x >> 1 shifts every bit one place right, discarding the lowest bit, which halves x by dropping any fraction. These operators support a handful of common, fast tricks: x & 1 tests whether x is odd, since that expression is 1 only when the lowest bit of x is set; x & (x - 1) clears the lowest set bit of x, because subtracting 1 flips every bit up to and including that lowest set bit, and ANDing with the original value keeps only the bits above it; and toggling a specific bit, checking whether it is set, or building a compact set of flags out of a single integer are all done by combining AND, OR, XOR, and shifts with the right mask. In JavaScript, bitwise operators convert their operands to 32-bit signed integers before operating and convert the result back to a regular number, so bitwise operations on values outside that 32-bit range can behave unexpectedly.
Examples
const a = 0b1010; // 10
const b = 0b0110; // 6
(a ^ b).toString(2); // '1100', 12
(a ^ a); // 0, XOR of a value with itself is always 0Each bit of the result is 1 exactly where a and b disagree: bit 3 (1 vs 0) and bit 2 (0 vs 1), giving 1100, which is 12; XORing any value with itself cancels every bit to 0, a trick used to swap variables or clear a value without a temporary.
function isOdd(x) { return (x & 1) === 1; }
isOdd(7); // true
isOdd(8); // false
function clearLowestSetBit(x) { return x & (x - 1); }
clearLowestSetBit(0b1010); // 0b1000, 8
clearLowestSetBit(0b1000); // 0, used to count set bits by repeating until 0x & 1 isolates the lowest bit to check odd or even; x & (x - 1) removes exactly the lowest 1 bit, a building block for efficiently counting how many bits are set in a number.
const READ = 1 << 0; // 0b001
const WRITE = 1 << 1; // 0b010
const EXEC = 1 << 2; // 0b100
let perms = READ | WRITE; // 0b011
const canWrite = (perms & WRITE) !== 0; // true
perms = perms & ~WRITE; // clear WRITE, back to 0b001Left-shifting 1 by different amounts builds distinct single-bit flags; OR combines flags into one integer, AND checks whether a flag is set, and AND with the bitwise NOT of a flag clears it, a compact way to store several booleans in one number.
Common mistakes
- Forgetting that JavaScript's bitwise operators convert numbers to 32-bit signed integers first, so bitwise operations on very large numbers can give surprising results.
- Confusing >> (sign-propagating right shift) with >>> (zero-fill right shift), which matters for negative numbers.
- Reaching for bit tricks like x & (x - 1) without a comment explaining what they do, making the code hard for others, or future you, to read.
Key takeaways
- AND, OR, and XOR combine bits according to simple rules, and XOR of a value with itself is always 0.
- Left shift multiplies by powers of two, and right shift divides by powers of two, discarding any remainder.
- x & 1 tests for odd, and x & (x - 1) clears the lowest set bit, two common building blocks for bit tricks.
- JavaScript's bitwise operators work on 32-bit signed integers internally, not arbitrary precision numbers.
What does x & (x - 1) do to the binary representation of x?
Where you see this
- Packing multiple boolean flags or permissions into a single integer to save memory and allow fast checks.
- Fast parity, power-of-two, and set-bit-counting checks used in low-level or performance-critical code.
- Hashing and checksum algorithms that mix bits with XOR and shifts.
- Working with binary protocols, packed color values, or file formats that store data at the bit level.