JavaScript > JavaScript Fundamentals > Operators > Bitwise operators
Understanding JavaScript Bitwise Operators
This guide provides a comprehensive overview of JavaScript bitwise operators, explaining their functionality, use cases, and best practices. It covers operators like AND (&), OR (|), XOR (^), NOT (~), Left Shift (<<), Right Shift (>>), and Zero-fill Right Shift (>>>).
What are Bitwise Operators?
Bitwise operators perform operations on the individual bits of a number. They treat numbers as sequences of bits (0s and 1s) rather than decimal values. Understanding these operators is crucial for tasks such as working with low-level data structures, manipulating flags, and optimizing performance in certain scenarios. JavaScript converts numbers to 32-bit integers before performing bitwise operations, then converts the result back to a JavaScript number.
Bitwise AND (&)
The bitwise AND operator (&) returns 1 only if both corresponding bits are 1; otherwise, it returns 0. In the example, 0101 & 0011 results in 0001 because only the rightmost bit is 1 in both numbers.
let a = 5; // Binary: 0101
let b = 3; // Binary: 0011
let result = a & b; // Binary: 0001 (Decimal: 1)
console.log(result);
Bitwise OR (|)
The bitwise OR operator (|) returns 1 if at least one of the corresponding bits is 1; it returns 0 only if both bits are 0. In the example, 0101 | 0011 results in 0111 because any bit that is 1 in either number becomes 1 in the result.
let a = 5; // Binary: 0101
let b = 3; // Binary: 0011
let result = a | b; // Binary: 0111 (Decimal: 7)
console.log(result);
Bitwise XOR (^)
The bitwise XOR (exclusive OR) operator (^) returns 1 if the corresponding bits are different; it returns 0 if the bits are the same. In the example, 0101 ^ 0011 results in 0110 because the bits in the 2nd and 3rd positions (from the right) differ.
let a = 5; // Binary: 0101
let b = 3; // Binary: 0011
let result = a ^ b; // Binary: 0110 (Decimal: 6)
console.log(result);
Bitwise NOT (~)
The bitwise NOT operator (~) inverts all the bits of a number. It changes 0s to 1s and 1s to 0s. Because JavaScript uses 32-bit signed integers, the NOT operator also changes the sign of the number. The twos-complement representation is used for negative numbers. In the example, ~5 results in -6 because the twos complement conversion causes the value to change.
let a = 5; // Binary: 0101
let result = ~a; // Binary: 11111111111111111111111111111010 (Decimal: -6)
console.log(result);
Left Shift (<<)
The left shift operator (<<) shifts all bits to the left by a specified number of positions. Zeros are added to the right. It effectively multiplies the number by 2 to the power of the shift amount. In the example, 5 << 2 shifts the bits of 5 two positions to the left, resulting in 20 (5 * 2^2).
let a = 5; // Binary: 0101
let result = a << 2; // Binary: 010100 (Decimal: 20)
console.log(result);
Right Shift (>>)
The right shift operator (>>) shifts all bits to the right by a specified number of positions. The sign bit (the leftmost bit) is propagated to fill the vacated positions. It effectively divides the number by 2 to the power of the shift amount, discarding any remainder. In the example, 20 >> 2 shifts the bits of 20 two positions to the right, resulting in 5 (20 / 2^2).
let a = 20; // Binary: 10100
let result = a >> 2; // Binary: 00101 (Decimal: 5)
console.log(result);
Zero-fill Right Shift (>>>)
The zero-fill right shift operator (>>>) shifts all bits to the right by a specified number of positions. Unlike the right shift operator (>>), the vacated positions are filled with zeros, regardless of the sign bit. This operator always produces a non-negative result. In the example, -5 >>> 2 shifts the bits of -5 two positions to the right, filling the vacated positions with zeros, resulting in a large positive number.
let a = -5; // Binary: 11111111111111111111111111111011
let result = a >>> 2; // Binary: 001111111111111111111111111110 (Decimal: 1073741822)
console.log(result);
Real-Life Use Case: Working with Flags
Bitwise operators are commonly used to work with flags. A flag is a boolean value represented by a single bit. Multiple flags can be combined into a single number, with each bit representing a different flag. This allows for efficient storage and manipulation of boolean data. For example, representing read, write, and execute permissions using bits.
Real-Life Use Case: Graphics Programming
Bitwise operations were frequently used in graphics programming, particularly in older systems with limited memory and processing power. They could be used for tasks like masking colors, clipping regions, and performing certain image manipulations. While modern graphics APIs often abstract away these low-level details, understanding bitwise operations can still be helpful for optimizing certain graphics algorithms.
Best Practices
Interview Tip
Be prepared to explain the functionality of each bitwise operator and provide examples of how they can be used in real-world scenarios. Demonstrate your understanding of bit manipulation and its potential benefits and drawbacks.
When to Use Them
Use bitwise operators when dealing with low-level data structures, manipulating flags, optimizing performance in specific scenarios (like older graphics systems or embedded systems), or when memory usage is a critical concern. Avoid them when the equivalent logical operators (&&, ||, !) provide a clearer and more readable solution.
Memory Footprint
Bitwise operators can be more memory-efficient when working with flags or sets of boolean values because multiple flags can be stored in a single number. This can be significant when dealing with a large number of flags or when memory is limited.
Alternatives
For simple boolean logic, use logical operators (&&, ||, !). For flag management, consider using an array of boolean values or an object with boolean properties if readability is a priority over memory efficiency. For more complex data structures, use appropriate data structures like sets or maps.
Pros
Cons
FAQ
-
Why do I get negative numbers when using the bitwise NOT operator?
JavaScript uses 32-bit signed integers, and the bitwise NOT operator inverts all the bits, including the sign bit. This results in the twos-complement representation of a negative number. -
Are bitwise operators used frequently in modern web development?
Not as frequently as other JavaScript operators, but they can be useful in specific scenarios such as working with binary data, managing flags, or optimizing performance in certain algorithms. Their primary use case is more prevalent in lower-level languages or systems programming. -
What is the difference between '>>' and '>>>' operators?
The '>>' operator performs a signed right shift, preserving the sign of the number by filling vacated bits with the sign bit. The '>>>' operator performs an unsigned right shift, filling vacated bits with zeros regardless of the sign. Therefore, '>>>' always results in a non-negative number.