Why Bitwise Operations Matter
Bitwise operations manipulate individual bits in a number. They are fast — a single CPU cycle — and memory-efficient: you can store 32 boolean flags in a single 32-bit integer instead of 32 separate variables. If you have ever used Unix permissions, React reconciliation flags, or feature toggles in a database, you have used bitwise operations.
AND (&) — Check If a Bit Is Set
AND compares each bit pair and returns 1 only if both bits are 1. Use AND to check whether a specific flag is enabled.
const READ = 0b001 // 1
const WRITE = 0b010 // 2
const EXEC = 0b100 // 4
const perms = READ | WRITE // 0b011 = 3
// Check if WRITE is set
if (perms & WRITE) {
console.log('Write is enabled') // ✓
}
if (perms & EXEC) {
console.log('Exec is enabled') // not reached
}
OR (|) — Set a Bit
OR returns 1 if either bit is 1. Use OR to enable a flag without affecting other flags.
let perms = READ // 0b001
perms = perms | WRITE // 0b011 — WRITE added
perms = perms | EXEC // 0b111 — EXEC added
XOR (^) — Toggle a Bit
XOR returns 1 if the bits are different. Use XOR to toggle a flag: if it is on, turn it off; if it is off, turn it on.
let flags = 0b101
flags = flags ^ 0b001 // 0b100 — first bit toggled off
flags = flags ^ 0b001 // 0b101 — first bit toggled back on
XOR is also used in simple checksums, swap-without-temp-variable tricks, and certain encryption algorithms.
NOT (~) — Invert All Bits
NOT flips every bit. In JavaScript (32-bit signed integers), ~n equals -(n + 1). A common trick: ~-1 equals 0 (falsy), so if (~str.indexOf('x')) was used before str.includes() existed. Avoid this pattern in modern code — use includes() instead.
Bit Shifting (<<, >>)
Left shift (<<) moves bits left, effectively multiplying by powers of 2. Right shift (>>) moves bits right, dividing by powers of 2 (rounding down).
1 << 0 // 1 (2⁰)
1 << 3 // 8 (2³)
1 << 10 // 1024 (2¹⁰)
255 >> 4 // 15 (integer division by 16)
Shift is commonly used to extract colour channels from a packed integer: (0xFF6B4A >> 16) & 0xFF extracts the red channel (255).
Real-World Use Cases
- Feature flags — Store multiple toggles in one database column:
if (user.features & BETA_ACCESS) - Permissions — Unix-style
rwxbits: read=4, write=2, execute=1 - Packed colours — RGB in a single integer:
(r << 16) | (g << 8) | b - Hash functions — All hash algorithms use extensive bit manipulation internally