SKU // 36

JavaScript Bitwise

Bitwise operators work on the individual binary digits (bits) of a number: the 1s and 0s underneath. You will not use them every day, but they show up in graphics, games, permission systems, and anywhere many yes/no settings are packed into one number. They are also a great way to understand how computers really store numbers.

// Numbers in Binary

Every whole number can be written in binary. Each position is worth double the one to its right:

//  8  4  2  1
//  0  1  0  1   = 4 + 1     = 5
//  1  1  0  1   = 8 + 4 + 1 = 13

console.log((13).toString(2));   // decimal to binary
console.log(0b1101);                // binary to decimal
1101 13

Numbers with only one bit set are the powers of two: 1, 2, 4, 8, 16, 32, 64... Setting more bits adds them up: 101101 is 32 + 8 + 4 + 1 = 45.

// JavaScript Uses 32 Bits

JavaScript normally stores numbers as 64-bit floating point. But bitwise operators work on 32-bit whole numbers. Before each bitwise operation, JavaScript converts the number to a 32-bit signed integer, and afterward converts the result back. Two consequences:

// The Operators

Op Name What happens Example
&AND1 where both bits are 15 & 1 = 1
|OR1 where either bit is 15 | 1 = 5
^XOR1 where the bits differ5 ^ 1 = 4
~NOTflips every bit~5 = -6
<<Zero fill left shiftbits move left, zeros come in on the right5 << 1 = 10
>>Signed right shiftbits move right, copies of the sign bit come in5 >> 1 = 2
>>>Zero fill right shiftbits move right, zeros come in on the left5 >>> 1 = 2

// AND, OR, XOR Worked Out

Line the two numbers up bit by bit, and apply the rule to each column:

//     5 = 0101
//     3 = 0011
// ------------
// 5 & 3 = 0001 = 1   (only where both are 1)
// 5 | 3 = 0111 = 7   (where either is 1)
// 5 ^ 3 = 0110 = 6   (where they differ)

console.log(5 & 3);
console.log(5 | 3);
console.log(5 ^ 3);
1 7 6
Watch out: & is not &&
Do not confuse these with the logical operators. && and || work with true/false; single & and | work on bits. 5 && 3 is 3, but 5 & 3 is 1. Typing one & in an if condition by accident often still "works" on true/false values, hiding the mistake until it doesn't.

// NOT and Negative Numbers

console.log(~5);
console.log(~0);
-6 -1

Why is ~5 equal to -6 and not 10? With only 4 bits, flipping 0101 would give 1010, which is 10. But JavaScript flips all 32 bits, including the sign bit:

//  5 = 00000000000000000000000000000101
// ~5 = 11111111111111111111111111111010   (sign bit is now 1: negative)

JavaScript stores negative numbers in a format called two's complement: a negative number is the bitwise NOT of the positive number, plus 1. So -5 is ~5 + 1, and flipping the bits of any n always gives -(n + 1):

000000000000000000000000000001106
11111111111111111111111111111010-6
0000000000000000000000000010100040
11111111111111111111111111011000-40

// Shifts

Shifting left by 1 doubles a whole number; shifting right by 1 halves it (dropping any remainder):

console.log(5 << 1);    // 0101 becomes 1010
console.log(5 << 3);    // 5 × 2 × 2 × 2
console.log(20 >> 2);   // 20 ÷ 2 ÷ 2
console.log(7 >> 1);    // remainder dropped
10 40 5 3

The two right shifts only differ for negative numbers. >> copies the sign bit in from the left, so the number stays negative. >>> pushes in zeros, so the sign bit becomes 0 and the result turns into a huge positive number:

console.log(-5 >> 1);     // sign kept
console.log(-5 >>> 1);    // sign bit replaced by 0
-3 2147483645

// Bitwise Assignment Operators

Like +=, each bitwise operator has an assignment version that does the operation and stores the result:

Operator Same as With x = 10
x &= 5x = x & 50
x |= 5x = x | 515
x ^= 5x = x ^ 515
x <<= 2x = x << 240
x >>= 1x = x >> 15
x >>>= 1x = x >>> 15

10 is 1010 and 5 is 0101: they share no bits, which is why & gives 0 and both | and ^ give 1111 (15).

// Real Use: Permission Flags

Each bit can stand for one yes/no setting. Many settings then fit in a single number:

const READ   = 1;   // 001
const WRITE  = 2;   // 010
const DELETE = 4;   // 100

let perms = READ | WRITE;               // turn on read and write: 011 = 3

console.log((perms & WRITE) !== 0);     // check: has write?
console.log((perms & DELETE) !== 0);    // check: has delete?

perms |= DELETE;                         // turn delete on:  111 = 7
perms &= ~WRITE;                         // turn write off:  101 = 5
console.log(perms.toString(2));
true false 101
Pattern
| turns a flag on, & checks it, & ~ turns it off, and ^ toggles it. That handful of moves covers nearly every real use.

// Handy Tricks

// Odd or even: the last bit of every odd number is 1
console.log(7 & 1);    // odd
console.log(8 & 1);    // even

// Decimal to binary, including negatives
console.log((-5 >>> 0).toString(2));

// Binary string to decimal
console.log(parseInt("1101", 2));
1 0 11111111111111111111111111111011 13

(-5).toString(2) would give "-101", a minus sign in front of 5's bits. Shifting by zero with >>> 0 first turns the number into its raw 32-bit pattern, so you see what is really stored.

A binary joke
There are only 10 kinds of people in the world: those who understand binary and those who don't.

// Quick Check

What is 12 & 10? (12 is 1100, 10 is 1010.)

  1. 8
  2. 14
  3. 6
  4. 22
Show answer
A. Only the leftmost column has a 1 in both: 1000 is 8. (14 is 12 | 10, and 6 is 12 ^ 10.)

What is 3 << 4?

Show answer
48. Each left shift doubles: 3 → 6 → 12 → 24 → 48. It is the same as 3 × 24, or 3 × 16.

With the permission flags above, which line turns WRITE off without touching the others?

  1. perms |= WRITE;
  2. perms &= ~WRITE;
  3. perms = WRITE;
  4. perms &&= WRITE;
Show answer
B. ~WRITE is all 1s except the write bit, so AND-ing with it clears just that bit. A turns write on, C wipes out every other flag, and D is a logical operator, not a bitwise one.

// Try It

  1. Click Open Playground and run it to see 12 and 10 in binary. Work out 12 & 10, 12 | 10, and 12 ^ 10 on paper, then log them to check
  2. Use << to compute 3 times 16 without using *
  3. Build the permission example and toggle WRITE on and off with ^=, logging perms.toString(2) each time
  4. Compare -8 >> 1 and -8 >>> 1. Explain the difference
// Video Walkthroughs
Last updated: Oct 10, 2026, 12:51 AM ET