Bitwise operators in JavaScript are fundamental to the language. These operators apply logical
operations to each bit of the operands. They consist of bitwise NOT (`~`

), bitwise AND
(`&`

), bitwise OR (`|`

), and bitwise XOR (`^`

), as well as their assignment variations `&=`

,
`|=`

, and `^=`

. This post discusses what they are and the best practices around them.

*The shift operators, <<, >>, and >>> as well as their assignment variations, are out of the
scope of this post.*

## What Are Bitwise Operators?

### How Are Integers Represented in Memory?

Integers in memory are represented by a certain number of bits. In JavaScript, integers, including BigInt, are represented using the method of two’s complement. For example, using 32 bits,

`20`

is represented as`0000 0000 0000 0000 0000 0000 0001 0100`

, and`-20`

is represented as`1111 1111 1111 1111 1111 1111 1110 1100`

.

### What Do Bitwise Operators Do?

Bitwise operators apply logical operations to each bit of the binary representation of integers. Assuming that the operands are 32-bit integers:

- Bitwise NOT
`~`

: Apply the logical operation NOT to each bit of an integer, i.e., flip every bit of an integer. For example,`~20`

is`-21`

, whose binary form is`1111 1111 1111 1111 1111 1111 1110 1011`

. - Bitwise AND
`&`

: Apply the logical operation AND to each pair of bits of two integers. For example,`20 & (-20)`

is`4`

, whose binary form is`0000 0000 0000 0000 0000 0000 0000 0100`

. - Bitwise OR
`|`

: Apply the logical operation OR to each pair of bits of two integers. For example,`20 | (-20)`

is`-4`

, whose binary form is`1111 1111 1111 1111 1111 1111 1111 1100`

. - Bitwise XOR
`^`

: Apply the logical operation XOR to each pair of bits of two integers. For example,`20 ^ (-20)`

is`-8`

, whose binary form is`1111 1111 1111 1111 1111 1111 1111 1000`

.

The table below summarizes the binary bitwise operators:

Operator | Operands/Result | |
---|---|---|

Decimal | Binary | |

Operand | `20` | `0000 0000 0000 0000 0000 0000 0001 0100` |

Operand | `-20` | `1111 1111 1111 1111 1111 1111 1110 1100` |

`&` | `4` | `0000 0000 0000 0000 0000 0000 0000 0100` |

`|` | `-4` | `1111 1111 1111 1111 1111 1111 1111 1100` |

`^` | `-8` | `1111 1111 1111 1111 1111 1111 1111 1000` |

### What Data Types Do JavaScript Bitwise Operators Work With?

In JavaScript, bitwise operators only apply to 32-bit integers and BigInt. Any operands with another type would be first cast to either of these.

For example, consider the expression `~1.1`

. Instead of applying the bitwise NOT operator on the
binary representation of `1.1`

(which is possible in other contexts), a JavaScript engine first
casts `1.1`

to `1`

, and then applies the bitwise NOT operator to `1`

as a 32-bit integer, which
results in `-2`

.

For another example, consider the expression `~0xaa11223344`

. `0xaa11223344`

has exceeded the
maximum of 32-bit representation. In this case, a JavaScript engine calculates `0xaa11223344`

modulo 2^{32}, which results in `0x11223344`

, and then applies the bitwise NOT operator
to it. The result is `-287454021`

. In fact, we can verify that `~0x11223344`

, `~0xa11223344`

,
`~0xaa11223344`

, and `~0xaaa11223344`

all result in the same number.

## How Are Bitwise Operators Used?

Bitwise operators are used for:

- enabling advanced or specialized algorithms, such as those in cryptography, and
- facilitating integers representing multiple Boolean variables, i.e., bitmasking.

Details of bitwise operators in advanced or specialized algorithms are out of the scope of this post. They are more suitable to be discussed in the context of those algorithms. This post focuses on bitmasking.

### Traditional Uses in C

While bitwise operators are not prevalently directly used in most JavaScript programs, they are often heavily used in a traditional programming language, such as C. The basic idea is that, instead of using multiple Boolean variables to represent a group of on/off statuses/options, it is more efficient to use bits in an integer. In this way, a 32-bit integer can represent up to 32 on/off statuses/options. This method is also referred to as bitmasking.

#### Example

For example, the POSIX C function `open`

opens a file. It takes an integer parameter `oflags`

,
which indicates the options that the caller wants to use, e.g.,

```
open("/path/to/file", O_WRONLY | O_CREAT);
```

Here, `O_WRONLY`

and `O_CREAT`

are two options, meaning write-only and creating the file if it
doesn’t exist, respectively. A possible implementation of `open`

defines `O_WRONLY`

as `1`

(binary
`01`

) and `O_CREAT`

as `2`

(binary `10`

). In this way, the caller can choose to turn on:

- both options (
`O_WRONLY | O_CREAT`

) or, - only one of them (
`O_WRONLY`

or`O_CREAT`

), or - neither (
`0`

).

Effectively, the lowest 2 bits of `oflags`

are used as two Boolean variables, representing the
`O_WRONLY`

and `O_CREAT`

options, respectively.

Bitwise operators also help the caller manipulate `oflags`

:

`oflags |= O_WRONLY`

turns on write-only,`oflags &= ~O_WRONLY`

turns off write-only, and`oflags ^ OWRONLY`

flips write-only.

Inside the function body of `open`

, the presences of these two options can be retrieved via
determining whether `oflags & O_WRONLY`

and `oflags & O_CREAT`

are not zero.

### Uses in JavaScript

In JavaScript, bitwise operators are used much less commonly than they are in C. Still, there are some occasions that they are used in this way.

One notable example is `Node.compareDocumentPosition`

. Its return value is a bitmask that
requires bitwise operators to retrieve the results. For example, consider the following HTML
document:

```
<!doctype html>
<html lang="en">
<body>
<p>This is a <em>paragraph</em>.</p>
</body>
</html>
```

You can open this HTML document, then run the following in the JavaScript console:

```
p = document.getElementsByTagName("p")[0];
em = document.getElementsByTagName("em")[0];
const relPosition = p.compareDocumentPosition(em);
console.log(relPosition);
```

The console prints `20`

. This magic number means nothing until we unmask them using bitwise
operators:

```
console.log(`Does p contains em? ${(relPosition & Node.DOCUMENT_POSITION_CONTAINED_BY) !== 0}`); // true
console.log(`Is em after p? ${(relPosition & Node.DOCUMENT_POSITION_FOLLOWING) !== 0}`); // true
console.log(`Does em contains p? ${(relPosition & Node.DOCUMENT_POSITION_CONTAINING) !== 0}`); // false
```

## When Should I Use Bitwise Operators?

As discussed in the *How Are Bitwise Operators Used?*, there are
two main use cases of bitwise operators: advanced/specialized algorithms and bitmasking.

**If we are implementing an advanced or specialized algorithm that requires bitwise operators, then
the answer is clearly yes.** But what about bitmasking? We need to first understand the most common
and idiomatic alternative to bitmasking in JavaScript.

### Representing a Group of Boolean Variables in JavaScript

In JavaScript, the most idiomatic way to represent a group of Boolean variables is using an object
with string keys and Boolean values. The C example above, if reimplemented in
JavaScript, its option `oflags`

would be an object. Borrowing the TypeScript syntax, its type looks
like:

```
interface OflagsType {
append: boolean;
creat: boolean;
// ...
}
```

The JavaScript `Node.compareDocumentPosition`

example, if reimplemented, should
return an object of type:

```
interface DocumentPosition {
documentPositionContainedBy: boolean;
documentPositionFollowing: boolean;
documentPositionContaining: boolean;
// ...
}
```

### Pros and Cons of Bitmasking

The table compares bitmasking to representing a group of Boolean variables using an object:

Bitmasking | Object | |
---|---|---|

Intuitive | ✓ | |

Less error-prone | ✓ | |

Easy to use | ✓ | |

Flexible with non-Boolean | ✓ | |

Efficient | ✓ | |

Compatible | - | - |

Based on this table, we should always prefer using an object unless:

- The situation demands the use of bitmasking for compatibility reasons, such as interacting with
`Node.compareDocumentPosition`

, or - performance gain of using bitmasking is important to the program. Keep in mind that this performance gain is tiny for each occurrence, but there still can be situations in which the performance gain is important, .e.g, when the bitmask is read or written many times in a short period of time.

Therefore, **we should normally use an object unless a special circumstance commands bitmasking.**

### A Decision Flow Chart

## Conclusion

- Bitwise operators apply to each bit of operands in their binary form.
- Bitwise operators are used for:
- enabling advanced or special algorithms, and
- facilitating integers representing multiple Boolean variables, i.e., bitmasking.

- In JavaScript, we usually prefer objects consisting of Boolean values over bitmasking unless a special circumstance justifies otherwise.