support@90-10.dev

JavaScript Bitwise Operators

Bitwise operators in JavaScript are powerful tools that allow us to manipulate individual bits in a number. These operators are often under-utilised due to their seemingly cryptic nature, but they can prove to be incredibly efficient in certain applications.

There are six JavaScript bitwise operators that can be used to manipulate the binary representation of integers:

1. Bitwise AND (&) - returns a 1 in each bit position where the corresponding bits of both operands are 1; returns 0 if either bit in the compared position is 0.

24           // binary:  0001 1000
10           // binary:  0000 1010

24 & 10 = 8  // binary:  0000 1000 

2. Bitwise OR (|) - returns a 1 in each bit position where the corresponding bits of either or both operands are 1; returns 0 if both bits are 0.

24            // binary:  0001 1000
10            // binary:  0000 1010

24 | 10 = 24  // binary:  0001 1010 

3. Bitwise XOR (^) - returns a 1 in each bit position where the corresponding bits of either but not both operands are 1; returns 0 if both bits are 0 or both are 1.

24            // binary:  0001 1000
10            // binary:  0000 1010

24 ^ 10 = 18  // binary:  0001 0010 

4. Bitwise NOT (~) - unary operator that inverts the bits of its operand. This will also flip the sign bit (the leftmost) so the result is negative.
NB: Bitwise operators treat their operands as a sequence of 32 bits.

10          // binary: 00000000 00000000 00000000 00001010
~10 = -11   // binary: 11111111 11111111 11111111 11110101

5. Left Shift (<<) - shifts the bits of the first operand to the left by the number of positions specified by the second operand - effectively a multiplication with 2 to the power of the second operand.

10            // binary:  0000 1010
10 << 2 = 40  // binary:  0100 1000

6. Sign Propagating Right Shift (>>) - shifts the bits of the first operand to the right by the number of positions specified by the second operand. The leftmost bits are filled with the sign bit (0 for positive numbers and 1 for negative numbers).

10            // binary:  1010
10 >> 2 = 2   // binary:  0010

-10             // 11111111 11111111 11111111 11110110
-10 >> 2 = -3   // 11111111 11111111 11111111 11111101

7. Zero-fill Right Shift (>>>) - shifts the bits of the first operand to the right by the number of positions specified by the second operand. The leftmost bits are filled with 0s.

10            // binary:  1010
10 >>> 2 = 2  // binary:  0010

-10                     // 11111111 11111111 11111111 11110110
-10 >>> 2 = 1073741821  // 00111111 11111111 11111111 11111101

Practical Examples

Fast and Efficient Odd-Even Check

Instead of using the modulo operator (%), the bitwise AND operator (&) can be used to quickly determine if a number is even or odd.

function isEven(num) {
  return !(num & 1);
}

function isOdd(num) {
  return num & 1;
}

console.log(isEven(10));  // prints: true
console.log(isOdd(5));    // prints: true

How? The bitwise AND will flip every bit to 0 with only the last one staying the same:

13           // binary:  1101
1            // binary:  0001
13 & 1 = 1   // binary:  0001

12           // binary:  1100
1            // binary:  0001
12 & 1 = 0   // binary:  0000

Extracting Specific Bits

Specific bits in a value can be used to signify features availability

function bitAtPosition(num, position) {
  return (num & (1 << position)) >> position;
}

const number = 0b1011010;  // decimal: 90
console.log(bitAtPosition(number, 3));  // prints: 1
console.log(bitAtPosition(number, 5));  // prints: 0

How?

  • 1 << position created a number with only one bit set to 1, at the position given - this is offen referred to as the mask
  • The bitwise AND is applied on the given number and the mask created above resulting in only the bit we're interesting in being making it through
  • the bit is then moved to the right based on its position - the result will contain the required bit