← All concepts
Bit Manipulation

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.

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 0

Each 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 0

x & 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 0b001

Left-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.
Check your understanding

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.

Practice this

Further reading

Previous
Greedy Algorithms