Docs
README
3.5 Bitwise Operators
Table of Contents
- โขWhat Are Bitwise Operators
- โขBinary Number Basics
- โขBitwise AND (&)
- โขBitwise OR (|)
- โขBitwise XOR (^)
- โขBitwise NOT (~)
- โขLeft Shift (<<)
- โขRight Shift (>>)
- โขZero-fill Right Shift (>>>)
- โขPractical Applications
What Are Bitwise Operators
Bitwise operators work on the binary representations of numbers, manipulating individual bits. JavaScript converts numbers to 32-bit signed integers before performing bitwise operations.
Why Learn Bitwise Operators?
| Use Case | Application |
|---|---|
| Flags & Permissions | Compact storage of multiple boolean values |
| Performance | Faster than multiplication/division by powers of 2 |
| Graphics | Color manipulation (RGB values) |
| Encryption | XOR-based encoding |
| Low-level | Embedded systems, protocols |
All Bitwise Operators
| Operator | Name | Description |
|---|---|---|
& | AND | Sets bit to 1 if both bits are 1 |
| | OR | Sets bit to 1 if at least one bit is 1 |
^ | XOR | Sets bit to 1 if exactly one bit is 1 |
~ | NOT | Inverts all bits |
<< | Left shift | Shifts bits left, fills with 0s |
>> | Right shift | Shifts bits right, preserves sign |
>>> | Zero-fill right shift | Shifts bits right, fills with 0s |
Binary Number Basics
Understanding Binary
Decimal 13 in binary:
Position: 8 4 2 1
Binary: 1 1 0 1
โ โ โ โ
Value: 8 + 4 + 0 + 1 = 13
Common Conversions
| Decimal | Binary | Hex |
|---|---|---|
| 0 | 0000 | 0x0 |
| 1 | 0001 | 0x1 |
| 5 | 0101 | 0x5 |
| 10 | 1010 | 0xA |
| 15 | 1111 | 0xF |
| 255 | 11111111 | 0xFF |
JavaScript Binary Methods
// Decimal to binary string
(13).toString(2); // "1101"
// Binary string to decimal
parseInt('1101', 2); // 13
// Binary literals (ES6)
const binary = 0b1101; // 13
Bitwise AND (&)
Returns 1 only if both bits are 1.
Truth Table
| A | B | A & B |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 0 |
| 1 | 0 | 0 |
| 1 | 1 | 1 |
Visual Example
12 = 1100
& 5 = 0101
โโโโโโโโโโ
4 = 0100
Position by position:
1 & 0 = 0
1 & 1 = 1
0 & 0 = 0
0 & 1 = 0
Common Uses
// Check if number is even (last bit is 0)
const isEven = (n) => (n & 1) === 0;
// Masking - extract specific bits
const extractLow4Bits = (n) => n & 0b1111;
// Clear specific bits
const clearBit3 = (n) => n & ~(1 << 2); // Clear 3rd bit (index 2)
Bitwise OR (|)
Returns 1 if at least one bit is 1.
Truth Table
| A | B | A | B |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 1 |
Visual Example
12 = 1100
| 5 = 0101
โโโโโโโโโโ
13 = 1101
Position by position:
1 | 0 = 1
1 | 1 = 1
0 | 0 = 0
0 | 1 = 1
Common Uses
// Set specific bits
const setBit3 = (n) => n | (1 << 2); // Set 3rd bit
// Combine flags
const READ = 0b001;
const WRITE = 0b010;
const EXECUTE = 0b100;
const permissions = READ | WRITE; // 0b011
// Floor positive numbers (faster than Math.floor)
const floor = (n) => n | 0; // 3.7 | 0 = 3
Bitwise XOR (^)
Returns 1 if bits are different.
Truth Table
| A | B | A ^ B |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 0 |
Visual Example
12 = 1100
^ 5 = 0101
โโโโโโโโโโ
9 = 1001
Position by position:
1 ^ 0 = 1
1 ^ 1 = 0
0 ^ 0 = 0
0 ^ 1 = 1
XOR Properties
// Self-inverse: a ^ a = 0
5 ^ 5; // 0
// Identity: a ^ 0 = a
5 ^ 0; // 5
// Commutativity: a ^ b = b ^ a
3 ^ 5; // Same as 5 ^ 3
// Associativity: (a ^ b) ^ c = a ^ (b ^ c)
Common Uses
// Toggle specific bits
const toggleBit = (n, pos) => n ^ (1 << pos);
// Swap without temp variable
let a = 5,
b = 3;
a = a ^ b; // a = 6
b = a ^ b; // b = 5
a = a ^ b; // a = 3
// Simple encryption/decryption
const encrypt = (char, key) => char ^ key;
const decrypt = (encrypted, key) => encrypted ^ key;
Bitwise NOT (~)
Inverts all bits (0 becomes 1, 1 becomes 0).
How It Works
~5 = ~(00000000000000000000000000000101)
= (11111111111111111111111111111010)
= -6 (in two's complement)
Formula: ~n = -(n + 1)
Examples
~5; // -6
~-3; // 2
~0; // -1
~-1; // 0
Common Uses
// Check if item exists in array (indexOf returns -1 if not found)
const arr = [1, 2, 3];
if (~arr.indexOf(2)) {
// ~(-1) = 0 (falsy), ~(1) = -2 (truthy)
console.log('Found!');
}
// Double NOT for integer truncation
~~3.7; // 3 (faster than Math.floor for positive)
~~-3.7; // -3 (different from Math.floor for negative!)
Left Shift (<<)
Shifts bits to the left, filling with 0s from the right.
Visual Example
5 << 2 = ?
5 = 00000101
โโโโโโ
After shift left by 2:
20 = 00010100
Lost bits โ 00000101 โ Added 0s
Mathematical Meaning
// Left shift by n = multiply by 2^n
5 << 1; // 10 (5 ร 2)
5 << 2; // 20 (5 ร 4)
5 << 3; // 40 (5 ร 8)
1 << 4; // 16 (1 ร 16 = 2^4)
Common Uses
// Fast multiplication by powers of 2
const multiply8 = (n) => n << 3;
// Create bit masks
const mask = 1 << 5; // 0b100000 = 32
// RGB to single color value
const rgb = (r, g, b) => (r << 16) | (g << 8) | b;
Right Shift (>>)
Shifts bits to the right, preserving the sign bit.
Visual Example (Positive)
20 >> 2 = ?
20 = 00010100
โโโโโโ
After shift right by 2:
5 = 00000101
Added 0s โ 00000101 โ Lost bits
Visual Example (Negative)
-20 >> 2 = ?
-20 = 11111111111111111111111111101100
โโโโโโ
After shift right by 2 (preserving sign):
-5 = 11111111111111111111111111111011
Sign bit preserved โ Added 1s โ Lost bits
Mathematical Meaning
// Right shift by n โ divide by 2^n (with floor)
20 >> 1; // 10 (20 รท 2)
20 >> 2; // 5 (20 รท 4)
-20 >> 2; // -5 (preserves sign)
Zero-fill Right Shift (>>>)
Shifts bits to the right, always filling with 0s (ignores sign).
Difference from >>
// Positive numbers: same result
20 >> 2; // 5
20 >>> 2; // 5
// Negative numbers: very different!
-20 >> 2; // -5 (sign preserved)
-20 >>> 2; // 1073741819 (treated as unsigned)
Common Uses
// Convert to unsigned 32-bit integer
const toUint32 = (n) => n >>> 0;
-1 >>> 0; // 4294967295 (max uint32)
-2 >>> 0; // 4294967294
Practical Applications
1. Permission Flags
// Define permission flags
const NONE = 0b0000; // 0
const READ = 0b0001; // 1
const WRITE = 0b0010; // 2
const EXECUTE = 0b0100; // 4
const DELETE = 0b1000; // 8
// Combine permissions
let userPerms = READ | WRITE; // 0b0011 = 3
// Check permission
const hasRead = (perms) => (perms & READ) !== 0;
const hasWrite = (perms) => (perms & WRITE) !== 0;
// Add permission
const addPerm = (perms, perm) => perms | perm;
// Remove permission
const removePerm = (perms, perm) => perms & ~perm;
// Toggle permission
const togglePerm = (perms, perm) => perms ^ perm;
2. Color Manipulation
// RGB to hex color
const rgbToHex = (r, g, b) => {
return '#' + ((1 << 24) | (r << 16) | (g << 8) | b).toString(16).slice(1);
};
// Hex to RGB
const hexToRgb = (hex) => {
const val = parseInt(hex.slice(1), 16);
return {
r: (val >> 16) & 0xff,
g: (val >> 8) & 0xff,
b: val & 0xff,
};
};
3. Fast Integer Operations
// Check if power of 2
const isPowerOf2 = (n) => n > 0 && (n & (n - 1)) === 0;
// Swap without temp
let x = 10,
y = 20;
x ^= y;
y ^= x;
x ^= y;
// Now x = 20, y = 10
// Round down to nearest power of 2
const floorPowerOf2 = (n) => {
n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
n |= n >> 8;
n |= n >> 16;
return n - (n >> 1);
};
4. Bit Counting
// Count set bits (population count)
const countBits = (n) => {
let count = 0;
while (n) {
count += n & 1;
n >>>= 1;
}
return count;
};
// Or using Brian Kernighan's algorithm (faster)
const countBitsFast = (n) => {
let count = 0;
while (n) {
n &= n - 1; // Clear lowest set bit
count++;
}
return count;
};
Summary
| Operator | Name | Example | Result | Use Case |
|---|---|---|---|---|
& | AND | 12 & 5 | 4 | Masking, check bits |
| | OR | 12 | 5 | 13 | Set bits, combine flags |
^ | XOR | 12 ^ 5 | 9 | Toggle, swap, encrypt |
~ | NOT | ~5 | -6 | Invert, indexOf check |
<< | Left shift | 5 << 2 | 20 | Multiply by 2^n |
>> | Right shift | 20 >> 2 | 5 | Divide by 2^n (signed) |
>>> | Zero-fill right | -1 >>> 0 | 4294967295 | Unsigned conversion |
Next Steps
After mastering bitwise operators, proceed to:
- โข3.6 Ternary Operator - Conditional expressions
- โขPractice bit manipulation problems
- โขImplement permission systems using flags