JavaScript Bitwise Operations
Working with binary representations and bit manipulation
🔢 What are Bitwise Operations?
Bitwise operations work directly with the binary representation of numbers. They manipulate individual bits and are very fast, making them useful for performance-critical applications and low-level programming.
// Simple bitwise AND example
console.log(5 & 3); // 1
// 5 in binary: 101
// 3 in binary: 011
// Result: 001 (which is 1)
Output:
1
Bitwise Operators
AND (&)
Returns 1 if both bits are 1
console.log(5 & 3); // 1
// 101 & 011 = 001
OR (|)
Returns 1 if either bit is 1
console.log(5 | 3); // 7
// 101 | 011 = 111
XOR (^)
Returns 1 if bits are different
console.log(5 ^ 3); // 6
// 101 ^ 011 = 110
NOT (~)
Flips all bits (inverts)
console.log(~5); // -6
// ~101 = ...11111010
🔹 Basic Bitwise Operations
Understanding the fundamental bitwise operators:
let a = 5; // Binary: 101
let b = 3; // Binary: 011
// AND (&) - both bits must be 1
console.log("5 & 3 =", a & b); // 1 (binary: 001)
// OR (|) - at least one bit must be 1
console.log("5 | 3 =", a | b); // 7 (binary: 111)
// XOR (^) - bits must be different
console.log("5 ^ 3 =", a ^ b); // 6 (binary: 110)
// NOT (~) - flips all bits
console.log("~5 =", ~a); // -6 (two's complement)
console.log("~3 =", ~b); // -4
// Helper function to see binary representation
function toBinary(num) {
return (num >>> 0).toString(2).padStart(8, '0');
}
console.log("5 in binary:", toBinary(5));
console.log("3 in binary:", toBinary(3));
console.log("5 & 3 in binary:", toBinary(5 & 3));
console.log("5 | 3 in binary:", toBinary(5 | 3));
console.log("5 ^ 3 in binary:", toBinary(5 ^ 3));
Output:
5 & 3 = 1
5 | 3 = 7
5 ^ 3 = 6
~5 = -6
~3 = -4
5 in binary: 00000101
3 in binary: 00000011
5 & 3 in binary: 00000001
5 | 3 in binary: 00000111
5 ^ 3 in binary: 00000110
🔹 Bit Shift Operations
Moving bits left or right:
let num = 5; // Binary: 101
// Left shift (<<) - multiply by 2^n
console.log("5 << 1 =", num << 1); // 10 (multiply by 2)
console.log("5 << 2 =", num << 2); // 20 (multiply by 4)
console.log("5 << 3 =", num << 3); // 40 (multiply by 8)
// Right shift (>>) - divide by 2^n (signed)
console.log("20 >> 1 =", 20 >> 1); // 10 (divide by 2)
console.log("20 >> 2 =", 20 >> 2); // 5 (divide by 4)
// Unsigned right shift (>>>) - always positive
console.log("-5 >> 1 =", -5 >> 1); // -3 (signed)
console.log("-5 >>> 1 =", -5 >>> 1); // 2147483645 (unsigned)
// Visual representation
function showShift(num, shift, direction) {
let original = toBinary(num);
let result = direction === 'left' ? num << shift : num >> shift;
let resultBinary = toBinary(result);
console.log(`${num} ${direction === 'left' ? '<<' : '>>'} ${shift}:`);
console.log(` Original: ${original} (${num})`);
console.log(` Result: ${resultBinary} (${result})`);
}
showShift(5, 2, 'left');
showShift(20, 2, 'right');
Output:
5 << 1 = 10
5 << 2 = 20
5 << 3 = 40
20 >> 1 = 10
20 >> 2 = 5
-5 >> 1 = -3
-5 >>> 1 = 2147483645
5 << 2:
Original: 00000101 (5)
Result: 00010100 (20)
20 >> 2:
Original: 00010100 (20)
Result: 00000101 (5)
🔹 Practical Bitwise Applications
Real-world uses of bitwise operations:
// 1. Check if number is even or odd
function isEven(num) {
return (num & 1) === 0; // Last bit is 0 for even numbers
}
console.log("Is 4 even?", isEven(4)); // true
console.log("Is 5 even?", isEven(5)); // false
// 2. Fast multiplication/division by powers of 2
function fastMultiply(num, power) {
return num << power; // Multiply by 2^power
}
function fastDivide(num, power) {
return num >> power; // Divide by 2^power
}
console.log("8 * 4 (fast):", fastMultiply(8, 2)); // 32
console.log("32 / 8 (fast):", fastDivide(32, 3)); // 4
// 3. Swap two numbers without temporary variable
function bitwiseSwap(a, b) {
console.log(`Before swap: a=${a}, b=${b}`);
a = a ^ b;
b = a ^ b;
a = a ^ b;
console.log(`After swap: a=${a}, b=${b}`);
return [a, b];
}
bitwiseSwap(5, 10);
// 4. Set, clear, and toggle specific bits
function setBit(num, position) {
return num | (1 << position);
}
function clearBit(num, position) {
return num & ~(1 << position);
}
function toggleBit(num, position) {
return num ^ (1 << position);
}
function checkBit(num, position) {
return (num & (1 << position)) !== 0;
}
let flags = 0; // Start with all flags off
console.log("Initial flags:", toBinary(flags));
flags = setBit(flags, 2); // Set bit 2
console.log("Set bit 2:", toBinary(flags));
flags = setBit(flags, 5); // Set bit 5
console.log("Set bit 5:", toBinary(flags));
console.log("Is bit 2 set?", checkBit(flags, 2)); // true
console.log("Is bit 3 set?", checkBit(flags, 3)); // false
flags = toggleBit(flags, 2); // Toggle bit 2
console.log("Toggle bit 2:", toBinary(flags));
Output:
Is 4 even? true
Is 5 even? false
8 * 4 (fast): 32
32 / 8 (fast): 4
Before swap: a=5, b=10
After swap: a=10, b=5
Initial flags: 00000000
Set bit 2: 00000100
Set bit 5: 00100100
Is bit 2 set? true
Is bit 3 set? false
Toggle bit 2: 00100000
🔹 Color Manipulation with Bitwise
Working with RGB colors using bitwise operations:
// RGB color as a single number (0xRRGGBB)
let color = 0xFF5733; // Orange color
// Extract RGB components
function getRed(color) {
return (color >> 16) & 0xFF;
}
function getGreen(color) {
return (color >> 8) & 0xFF;
}
function getBlue(color) {
return color & 0xFF;
}
console.log("Color:", color.toString(16).toUpperCase());
console.log("Red component:", getRed(color));
console.log("Green component:", getGreen(color));
console.log("Blue component:", getBlue(color));
// Create color from RGB components
function createColor(r, g, b) {
return (r << 16) | (g << 8) | b;
}
let newColor = createColor(128, 255, 64);
console.log("New color:", newColor.toString(16).toUpperCase());
// Modify color components
function setRed(color, red) {
return (color & 0x00FFFF) | (red << 16);
}
function setGreen(color, green) {
return (color & 0xFF00FF) | (green << 8);
}
function setBlue(color, blue) {
return (color & 0xFFFF00) | blue;
}
let modifiedColor = setGreen(color, 128);
console.log("Modified color:", modifiedColor.toString(16).toUpperCase());
Output:
Color: FF5733
Red component: 255
Green component: 87
Blue component: 51
New color: 80FF40
Modified color: FF8033
🔹 Permission Systems with Bitwise
Using bitwise operations for permission flags:
// Permission constants (powers of 2)
const PERMISSIONS = {
READ: 1, // 001
WRITE: 2, // 010
EXECUTE: 4, // 100
DELETE: 8, // 1000
ADMIN: 16 // 10000
};
// User permissions
let userPermissions = 0;
// Grant permissions
function grantPermission(permissions, permission) {
return permissions | permission;
}
// Revoke permissions
function revokePermission(permissions, permission) {
return permissions & ~permission;
}
// Check if user has permission
function hasPermission(permissions, permission) {
return (permissions & permission) === permission;
}
// Grant some permissions
userPermissions = grantPermission(userPermissions, PERMISSIONS.READ);
userPermissions = grantPermission(userPermissions, PERMISSIONS.WRITE);
console.log("User permissions:", userPermissions.toString(2).padStart(5, '0'));
console.log("Can read?", hasPermission(userPermissions, PERMISSIONS.READ));
console.log("Can write?", hasPermission(userPermissions, PERMISSIONS.WRITE));
console.log("Can execute?", hasPermission(userPermissions, PERMISSIONS.EXECUTE));
// Grant multiple permissions at once
userPermissions = grantPermission(userPermissions, PERMISSIONS.EXECUTE | PERMISSIONS.DELETE);
console.log("Updated permissions:", userPermissions.toString(2).padStart(5, '0'));
// Check multiple permissions
function hasAllPermissions(permissions, requiredPermissions) {
return (permissions & requiredPermissions) === requiredPermissions;
}
let requiredForAdmin = PERMISSIONS.READ | PERMISSIONS.WRITE | PERMISSIONS.EXECUTE;
console.log("Has admin requirements?", hasAllPermissions(userPermissions, requiredForAdmin));
Output:
User permissions: 00011
Can read? true
Can write? true
Can execute? false
Updated permissions: 01111
Has admin requirements? true