JavaScript Bitwise Operations
Bitwise operators work on 32-bit signed integers. They perform operations on the binary (bit-level) representation of numbers. While rarely used in everyday JavaScript, they are important for flags, permissions, low-level optimization, and understanding how computers process data.
Bitwise AND (&), OR (|), XOR (^)
AND (&) returns 1 for each bit position where both operands have 1. OR (|) returns 1 where at least one operand has 1. XOR (^) returns 1 where exactly one operand has 1.
let a = 5; // binary: 0101
let b = 3; // binary: 0011
// AND: both bits must be 1
console.log(a & b);
console.log((5).toString(2) + " & " + (3).toString(2) + " = " + (a & b).toString(2));
// OR: at least one bit must be 1
console.log(a | b);
console.log((5).toString(2) + " | " + (3).toString(2) + " = " + (a | b).toString(2));
// XOR: exactly one bit must be 1
console.log(a ^ b);
console.log((5).toString(2) + " ^ " + (3).toString(2) + " = " + (a ^ b).toString(2));Bitwise NOT (~)
The NOT operator (~) inverts all bits. For a 32-bit integer, ~n equals -(n + 1). This is because JavaScript uses two's complement representation for signed integers.
console.log(~5);
console.log(~0);
console.log(~-1);
console.log(~-3);
// Pattern: ~n = -(n + 1)
console.log(~5 === -(5 + 1));
// Historical trick: ~indexOf() for boolean check
let str = "Hello World";
if (~str.indexOf("World")) {
console.log("Found 'World'");
}
// Modern: use includes() instead
console.log(str.includes("World"));Left Shift (<<) and Right Shift (>>)
Left shift (<<) moves bits to the left, filling with zeros on the right. Each shift left doubles the value. Right shift (>>) moves bits to the right, preserving the sign bit. Each shift right halves the value.
// Left shift: multiply by 2^n
console.log(5 << 1);
console.log(5 << 2);
console.log(5 << 3);
console.log(1 << 10);
// Right shift: divide by 2^n (integer result)
console.log(20 >> 1);
console.log(20 >> 2);
console.log(20 >> 3);
// Right shift preserves sign
console.log(-20 >> 1);
console.log(-20 >> 2);Unsigned Right Shift (>>>)
The unsigned right shift (>>>) shifts bits to the right and fills the leftmost bits with zeros (ignoring the sign). This converts negative numbers to large positive numbers because the sign bit becomes 0.
// Regular right shift preserves sign
console.log(-1 >> 0);
// Unsigned right shift fills with zeros
console.log(-1 >>> 0);
// Useful to convert to unsigned 32-bit integer
console.log(-1 >>> 0);
console.log((-5 >>> 0).toString(2));
// Positive numbers are the same for >> and >>>
console.log(20 >> 2);
console.log(20 >>> 2);Practical Use Cases
Bitwise operators are commonly used for permission flags, color manipulation, and performance-critical operations where bit-level control is needed.
// Permission system using bitwise flags
const READ = 1; // 001
const WRITE = 2; // 010
const EXECUTE = 4; // 100
// Combine permissions with OR
let userPerms = READ | WRITE;
console.log("User perms:", userPerms);
// Check permission with AND
console.log("Can read?", (userPerms & READ) !== 0);
console.log("Can execute?", (userPerms & EXECUTE) !== 0);
// Add permission with OR
userPerms = userPerms | EXECUTE;
console.log("After adding execute:", userPerms);
console.log("Can execute?", (userPerms & EXECUTE) !== 0);
// Remove permission with AND + NOT
userPerms = userPerms & ~WRITE;
console.log("After removing write:", userPerms);
console.log("Can write?", (userPerms & WRITE) !== 0);| Operator | Name | Example | Result | Description |
|---|---|---|---|---|
| & | AND | 5 & 3 | 1 | 1 if both bits are 1 |
| | | OR | 5 | 3 | 7 | 1 if either bit is 1 |
| ^ | XOR | 5 ^ 3 | 6 | 1 if bits differ |
| ~ | NOT | ~5 | -6 | Inverts all bits |
| << | Left Shift | 5 << 1 | 10 | Shift left, fill with 0 |
| >> | Right Shift | 20 >> 2 | 5 | Shift right, keep sign |
| >>> | Unsigned Right Shift | -1 >>> 0 | 4294967295 | Shift right, fill with 0 |