Editor’s note: This article was last updated by Ibiyemi Adewakun on 13 April 2023. Want to read up on some other JavaScript operators? Check out our posts on optional chaining and nullish coalescing in JavaScript and the JavaScript pipe operator proposal.
JavaScript provides several kinds of operators, making it possible to carry out basic operations on simple values such as arithmetic operations, assignment operations, logical operations, bitwise operations, etc.
We often see JavaScript code that contains a mix of assignment operators, arithmetic operators, and logical operators. However, we don’t get to see bitwise operators in use that much.
In this tutorial, we will take a look at all the JavaScript bitwise operators and try to understand how they are evaluated. We will also look at a few interesting applications for bitwise operators in writing simple JavaScript programs. This will require us to take a little peek at how JavaScript bitwise operators represent their operands as signed 32-bit integers. Jump ahead in the article for a reference chart of all of the JavaScript bitwise operators we’ll cover in this article.
Jump ahead:
~
— Bitwise NOT&
— Bitwise AND|
— Bitwise OR^
— Bitwise XOR<<
— Left shift>>
— Sign-propagating right shift>>>
— Zero-fill right shift~
) operatorThe ~
operator is a unary operator, meaning it takes only one operand. The ~
operator performs a NOT operation on every bit of its operand. The result of a NOT operation is called a complement. The complement of an integer is formed by inverting every bit of the integer.
For a given integer — say, 170
— the complement can be computed using the ~
operator as follows:
// 170 => 00000000000000000000000010101010 // -------------------------------------- // ~ 00000000000000000000000010101010 // -------------------------------------- // = 11111111111111111111111101010101 // -------------------------------------- // = -171 (decimal) console.log(~170); // -171
JavaScript bitwise operators convert their operands to 32-bit signed integers in two’s complement format. Hence, when the ~
operator is used on an integer, the resulting value is the two’s complement of the integer. The two’s complement of an integer A
is given by -(A + 1)
:
~170 => -(170 + 1) => -171
Here are a few points to note about the 32-bit signed integers used by JavaScript bitwise operators:
0
for positive integers, and 1
for negative integers(2^31 - 1)
, which is 2147483647
, while the minimum integer is -(2^31)
, which is -2147483648
Here are the 32-bit sequence representations of some important numbers:
0 => 00000000000000000000000000000000 -1 => 11111111111111111111111111111111 2147483647 => 01111111111111111111111111111111 -2147483648 => 10000000000000000000000000000000
From the above representations, it is evident that:
~0 => -1 ~-1 => 0 ~2147483647 => -2147483648 ~-2147483648 => 2147483647
One of the most common use cases for the bitwise NOT operator is in combination with the found index. Let’s take a look at how it is used.
Most built-in objects in JavaScript, such as arrays and strings, have some useful methods that can be used to check for the presence of an item in the array or a substring within the string. Here are some of those methods:
Array.indexOf()
Array.lastIndexOf()
Array.findIndex()
String.indexOf()
String.lastIndexOf()
String.search()
These methods all return the zero-based index of the item or substring, if it is found. Otherwise, they return -1
. For example:
const numbers = [1, 3, 5, 7, 9]; console.log(numbers.indexOf(5)); // 2 console.log(numbers.indexOf(8)); // -1
In the snippet above, we see that when an item is not found, we get -1
in return. But it is easier to confirm if this item is missing or exists using a Boolean true or false and this is where the bitwise NOT operator helps.
Remember that the complement of -1
is 0
(zero), and in JavaScript, a zero-value when made Boolean is false. This means we can check for the complement of our found index and convert it to a Boolean.
Here is what that will look like:
function foundIndex (index) { return Boolean(~index); }
In the above code snippet, the ~
operator, when used on -1
, evaluates to 0
, which is a falsy value. Hence, using Boolean()
to cast a falsy value will return false
. For every other index value, true
is returned because in JavaScript any non-zero value (even negative numbers) is truthy. So the previous code snippet can be modified as follows:
const numbers = [1, 3, 5, 7, 9]; console.log(foundIndex(numbers.indexOf(5))); // true console.log(foundIndex(numbers.indexOf(8))); // false
&
) operatorThe &
operator performs an AND operation on each pair of corresponding bits of its operands. The &
operator returns 1
only if both bits are 1; otherwise, it returns 0
. Thus, the result of an AND operation is the equivalent of multiplying each pair of corresponding bits.
For a pair of bits, here are the possible values of an AND operation:
(0 & 0) === 0 // 0 x 0 = 0 (0 & 1) === 0 // 0 x 1 = 0 (1 & 0) === 0 // 1 x 0 = 0 (1 & 1) === 1 // 1 x 1 = 1
The &
operator is commonly used in bit masking applications to ensure that certain bits are turned off for a given sequence of bits. This is based on the fact that for any bit A
:
(A & 0 = 0)
– the bit is always turned off by a corresponding 0
bit(A & 1 = A)
– the bit remains unchanged when paired with a corresponding 1
bitFor example, say we have an 8-bit integer, and we want to ensure that the first four bits are turned off (set to 0
). The &
operator can be used to achieve this as follows:
0b11110000
. Note that the first 4 bits of the bit mask are set to 0
, while every other bit is set to 1
&
operation using the 8-bit integer and the created bit mask:
const mask = 0b11110000;// 222 => 11011110// (222 & mask) // ------------ // 11011110 // & 11110000 // ------------ // = 11010000 // ------------ // = 208 (decimal)console.log(222 & mask); // 208
The &
operator has some other useful bit masking applications. One such application is in determining whether one or more bits are set for a given sequence of bits. For example, say we want to check if the fifth bit is set for a given decimal number. Here is how we can use the &
operator to do that:
const mask = 0b10000;
&
operation using the decimal number and the bit mask as operands, and compare the result with the bit mask. If all the target bits are set for the decimal number, the result of the &
operation will be equal to the bit mask. Note that the 0
bits in the bit mask will effectively turn off the corresponding bits in the decimal number, because A & 0 = 0:
// 34 => 100010 // (34 & mask) => (100010 & 010000) = 000000 console.log((34 & mask) === mask); // false// 50 => 110010 // (50 & mask) => (110010 & 010000) = 010000 console.log((50 & mask) === mask); // true
The use of the &
operator in checking for set bits for a decimal number can be extended to check whether a given decimal number is even or odd. To achieve this, 1
is used as the bit mask (to determine whether the first bit or rightmost bit is set). For integers, the least significant bit (first bit or rightmost bit) can be used to determine whether the number is even or odd. If the least significant bit is turned on (set to 1
), the number is odd; otherwise, the number is even:
function isOdd (int) { return (int & 1) === 1; } function isEven (int) { return (int & 1) === 0; } console.log(isOdd(34)); // false console.log(isOdd(-63)); // true console.log(isEven(-12)); // true console.log(isEven(199)); // false
Before proceeding to the next operator, here are some useful identities for bitwise AND &
operations (for any signed 32-bit integer A
):
(A & 0) === 0 (A & ~A) === 0 (A & A) === A (A & -1) === A
|
) operatorThe |
operator performs an OR operation on each pair of corresponding bits of its operands. The |
operator returns 0
only if both bits are 0; otherwise, it returns 1
.
For a pair of bits, here are the possible values of an OR operation:
(0 | 0) === 0 (0 | 1) === 1 (1 | 0) === 1 (1 | 1) === 1
In bit masking applications, the |
operator can be used to ensure that certain bits in a sequence of bits are turned on (set to 1
). This is based on the fact that for any given bit A
:
(A | 0 = A)
— The bit remains unchanged when paired with a corresponding 0
bit(A | 1 = 1)
— The bit is always turned on by a corresponding 1
bitFor example, say we have an 8-bit integer and we want to ensure that all the even-position bits (second, fourth, sixth, eighth) are turned on (set to 1
). The |
operator can be used to achieve this as follows:
0b10101010
. Note that the even-positioned bits of the bit mask are set to 1
, while every other bit is set to 0
|
operation using the 8-bit integer and the created bit mask:
const mask = 0b10101010;// 208 => 11010000// (208 | mask) // ------------ // 11010000 // | 10101010 // ------------ // = 11111010 // ------------ // = 250 (decimal)console.log(208 | mask); // 250
Before proceeding to the next operator, here are some useful identities for bitwise OR |
operations (for any signed 32-bit integer A
):
(A | 0) === A (A | ~A) === -1 (A | A) === A (A | -1) === -1
^
) operatorThe ^
operator performs an XOR (exclusive-OR) operation on each pair of corresponding bits of its operands. The ^
operator returns 0
if both bits are the same (either 0 or 1); otherwise, it returns 1
.
For a pair of bits, here are the possible values of an XOR operation:
(0 ^ 0) === 0 (0 ^ 1) === 1 (1 ^ 0) === 1 (1 ^ 1) === 0
In bit masking applications, the ^
operator is commonly used for toggling or flipping certain bits in a sequence of bits. This is based on the fact that for any given bit A
:
0
bit, e.g., (A ^ 0 = A)
1
bit:(A ^ 1 = 1)
— if A
is 0
(A ^ 1 = 0)
— if A
is 1
For example, say we have an 8-bit integer and we want to ensure that every bit is toggled except the least significant (first) and most significant (eighth) bits. The ^
operator can be used to achieve this as follows:
0b01111110
. Note that the bits to be toggled are set to 1
, while every other bit is set to 0
^
operation using the 8-bit integer and the created bit mask:
const mask = 0b01111110;// 208 => 11010000// (208 ^ mask) // ------------ // 11010000 // ^ 01111110 // ------------ // = 10101110 // ------------ // = 174 (decimal)console.log(208 ^ mask); // 174
Before proceeding to the next operator, here are some useful identities for bitwise XOR ^
operations (for any signed 32-bit integer A
):
(A ^ 0) === A (A ^ ~A) === -1 (A ^ A) === 0 (A ^ -1) === ~A
From the identities listed above, it is evident that an XOR operation on A
and -1
is equivalent to a NOT operation on A
. This means the foundIndex()
function from before can also be written like:
function foundIndex(index) { return Boolean(index ^ -1); }
<<
) operatorThe left shift (<<
) operator takes two operands. The first operand is an integer, while the second operand is the number of bits of the first operand to be shifted to the left. Zero (0
) bits are shifted in from the right, while the excess bits that have been shifted off to the left are discarded.
For example, consider the integer 170
. Let’s say we want to shift three bits to the left. We can use the <<
operator as follows:
// 170 => 00000000000000000000000010101010 // 170 << 3 // -------------------------------------------- // (000)00000000000000000000010101010(***) // -------------------------------------------- // = (***)00000000000000000000010101010(000) // -------------------------------------------- // = 00000000000000000000010101010000 // -------------------------------------------- // = 1360 (decimal) console.log(170 << 3); // 1360
The left shift bitwise operator (<<
) can be defined using the following JavaScript expressions:
(A << B) => A * (2 ** B) => A * Math.pow(2, B)
Hence, looking back at the previous example:
(170 << 3) => 170 * (2 ** 3) => 170 * 8 => 1360
One very useful application of the left shift (<<
) operator is converting colors from an RGB representation to a hexadecimal representation.
The color value for each component of an RGB color is between 0 - 255
. Simply put, each color value can be represented perfectly by 8 bits:
0 => 0b00000000 (binary) => 0x00 (hexadecimal) 255 => 0b11111111 (binary) => 0xff (hexadecimal)
Thus, the color itself can be perfectly represented by 24 bits (8 bits each for red, green, and blue components). The first 8 bits starting from the right will represent the blue component, the next 8 bits will represent the green component, and the 8 bits after that will represent the red component:
(binary) => 11111111 00100011 00010100 (red) => 11111111 => ff => 255 (green) => 00100011 => 23 => 35 (blue) => 00010100 => 14 => 20 (hex) => ff2314
Now that we understand how to represent the color as a 24-bit sequence, let’s see how we can compose the 24 bits of the color from the values of the color’s individual components. Let’s say we have a color represented by rgb(255, 35, 20)
. Here is how we can compose the bits:
(red) => 255 => 00000000 00000000 00000000 11111111 (green) => 35 => 00000000 00000000 00000000 00100011 (blue) => 20 => 00000000 00000000 00000000 00010100 // Rearrange the component bits and pad with zeroes as necessary // Use the left shift operator (red << 16) => 00000000 11111111 00000000 00000000 (green << 8) => 00000000 00000000 00100011 00000000 (blue) => 00000000 00000000 00000000 00010100 // Combine the component bits together using the OR (|) operator // ( red << 16 | green << 8 | blue ) 00000000 11111111 00000000 00000000 | 00000000 00000000 00100011 00000000 | 00000000 00000000 00000000 00010100 // ----------------------------------------- 00000000 11111111 00100011 00010100 // -----------------------------------------
Now that the procedure is pretty clear, here is a simple function that takes the RGB values of a color as an input array and returns the corresponding hexadecimal representation of the color based on the above procedure:
function rgbToHex ([red = 0, green = 0, blue = 0] = []) { return `#${(red << 16 | green << 8 | blue).toString(16)}`; }
With our function snippet that implements the left shift operator, we can create a simple page that shows how colors can be converted from RGB to Hex codes and sets two rectangles’ colors using both codes. The full HTML code for this is available here:
The sign-propagating right shift (>>
) operator takes two operands. The first operand is an integer, while the second operand is the number of bits of the first operand to be shifted to the right.
The excess bits that have been shifted off to the right are discarded, whereas copies of the sign bit (leftmost bit) are shifted in from the left. As a result, the sign of the integer is always preserved, hence the name sign-propagating right shift.
For example, consider the integers 170
and -170
. Let’s say we want to shift three bits to the right. We can use the >>
operator as follows:
// 170 => 00000000000000000000000010101010 // -170 => 11111111111111111111111101010110 // 170 >> 3 // -------------------------------------------- // (***)00000000000000000000000010101(010) // -------------------------------------------- // = (000)00000000000000000000000010101(***) // -------------------------------------------- // = 00000000000000000000000000010101 // -------------------------------------------- // = 21 (decimal) // -170 >> 3 // -------------------------------------------- // (***)11111111111111111111111101010(110) // -------------------------------------------- // = (111)11111111111111111111111101010(***) // -------------------------------------------- // = 11111111111111111111111111101010 // -------------------------------------------- // = -22 (decimal) console.log(170 >> 3); // 21 console.log(-170 >> 3); // -22
The sign-propagating right shift bitwise operator (>>
) can be described by the following JavaScript expressions:
(A >> B) => Math.floor(A / (2 ** B)) => Math.floor(A / Math.pow(2, B))
Thus, looking back at the previous example:
(170 >> 3) => Math.floor(170 / (2 ** 3)) => Math.floor(170 / 8) => 21 (-170 >> 3) => Math.floor(-170 / (2 ** 3)) => Math.floor(-170 / 8) => -22
One very good application of the right shift (>>
) operator is extracting RGB color values from a color. When the color is represented in RGB, it is very easy to distinguish between the red, green, and blue color component values. However, it will take a bit more effort for a color represented as hexadecimal.
In the previous section, we saw the procedure for composing the bits of a color from the bits of its individual components (red, green, and blue). If we work through that procedure backwards, we will be able to extract the values of the individual components of the color. Let’s give that a shot.
Let’s say we have a color represented by the hexadecimal notation #ff2314
. Here is the signed 32-bit representation of the color:
(color) => ff2314 (hexadecimal) => 11111111 00100011 00010100 (binary) // 32-bit representation of color 00000000 11111111 00100011 00010100
To get the individual components, we will right-shift the color bits by multiples of 8 as necessary until we get the target component bits as the first 8 bits from the right. Since the most significant bit of the 32 bits for the color is 0
, we can safely use the sign-propagating right shift (>>
) operator for this:
color => 00000000 11111111 00100011 00010100 // Right shift the color bits by multiples of 8 // Until the target component bits are the first 8 bits from the right red => color >> 16 => 00000000 11111111 00100011 00010100 >> 16 => 00000000 00000000 00000000 11111111 green => color >> 8 => 00000000 11111111 00100011 00010100 >> 8 => 00000000 00000000 11111111 00100011 blue => color >> 0 => color => 00000000 11111111 00100011 00010100
Now that we have the target component bits as the first 8 bits from the right, we need a way to mask out every other bits except the first 8 bits. That brings us back to the AND (&
) operator. Remember that the &
operator can be used to ensure that certain bits are turned off.
Let’s start by creating the required bit mask. That would look like this:
mask => 00000000 00000000 00000000 11111111 => 0b11111111 (binary) => 0xff (hexadecimal)
With the bit mask ready, we can carry out an AND (&
) operation on each of the results from the previous right-shifting operations using the bit mask to extract the target component bits:
red => color >> 16 & 0xff => 00000000 00000000 00000000 11111111 => & 00000000 00000000 00000000 11111111 => = 00000000 00000000 00000000 11111111 => 255 (decimal) green => color >> 8 & 0xff => 00000000 00000000 11111111 00100011 => & 00000000 00000000 00000000 11111111 => = 00000000 00000000 00000000 00100011 => 35 (decimal) blue => color & 0xff => 00000000 11111111 00100011 00010100 => & 00000000 00000000 00000000 11111111 => = 00000000 00000000 00000000 00010100 => 20 (decimal)
Based on the above procedure, here is a simple function that takes a hex color string (with six hexadecimal digits) as input and returns the corresponding array of RGB color component values:
function hexToRgb (hex) { hex = hex.replace(/^#?([0-9a-f]{6})$/i, '$1'); hex = Number(`0x${hex}`); return [ hex >> 16 & 0xff, // red hex >> 8 & 0xff, // green hex & 0xff // blue ]; }
With this function, we can create an HTML page to illustrate how colors can be converted from Hex codes to RGB and sets two rectangle colors using each codes. The HTML code for this is available here:
>>>
) operatorThe zero-fill right shift (>>>
) operator behaves pretty much like the sign-propagating right shift (>>
) operator. However, the key difference is in the bits that are shifted in from the left.
As the name implies, 0
bits are always shifted in from the left. As a result, the >>>
operator always returns an unsigned 32-bit integer because the sign bit of the resulting integer is always 0
. For positive integers, both >>
and >>>
will always return the same result.
For example, consider the integers 170
and -170
. Let’s say we want to shift three bits to the right. We can use the >>>
operator as follows:
// 170 => 00000000000000000000000010101010 // -170 => 11111111111111111111111101010110 // 170 >>> 3 // -------------------------------------------- // (***)00000000000000000000000010101(010) // -------------------------------------------- // = (000)00000000000000000000000010101(***) // -------------------------------------------- // = 00000000000000000000000000010101 // -------------------------------------------- // = 21 (decimal) // -170 >>> 3 // -------------------------------------------- // (***)11111111111111111111111101010(110) // -------------------------------------------- // = (000)11111111111111111111111101010(***) // -------------------------------------------- // = 00011111111111111111111111101010 // -------------------------------------------- // = 536870890 (decimal) console.log(170 >>> 3); // 21 console.log(-170 >>> 3); // 536870890
Before we wrap up this tutorial, let’s consider another common application of bitwise operators and bit masking: config flags.
Let’s say we have a function that accepts a couple of Boolean options that can be used to control how the function runs or the kind of value it returns. One possible way to create this function is by passing all the options as arguments to the function, probably with some default values, like so:
function doSomething (optA = true, optB = true, optC = false, optD = true, ...) { // something happens here... }
Surely, this isn’t so convenient. Here are two cases in which this approach starts getting quite problematic:
One way to solve the issues with the previous approach would be to use an object for the config options, like so:
const defaultOptions = { optA: true, optB: true, optC: false, optD: true, ... }; function doSomething (options = defaultOptions) { // something happens here... }
This approach is very elegant, and you’ve most likely seen it used, or even used it yourself at some point or another. With this approach, however, the options
argument will always be an object, which can be considered overkill for just configuration options.
If all the options take Boolean values, we could use an integer instead of an object to represent the options. In this case, certain bits of the integer will be mapped to designated options. If a bit is turned on (set to 1
), the designated option’s value is true
; otherwise, it is false
.
We can demonstrate this approach using a simple example. Let’s say we have a function that normalizes the items of an array list containing numbers and returns the normalized array. The returned array can be controlled by three options, namely:
We can use an integer with three bits to represent these options, each bit being mapped to an option. The following code snippet shows the option flags:
const LIST_FRACTION = 0x1; // (001) const LIST_UNIQUE = 0x2; // (010) const LIST_SORTED = 0x4; // (100)
To activate one or more options, the |
operator can be used to combine the corresponding flags as necessary. For example, we can create a flag that activates all the options, as follows:
const LIST_ALL = LIST_FRACTION | LIST_UNIQUE | LIST_SORTED; // (111)
Again, let’s say we want only the fraction and sorted options to be activated by default. We could use the |
operator again, as follows:
const LIST_DEFAULT = LIST_FRACTION | LIST_SORTED; // (101)
While this doesn’t look bad with just three options, it tends to become quite messy when there are so many options, and a lot of them are required to be activated by default. In such a scenario, a better approach will be to deactivate the unwanted options using the ^
operator:
const LIST_DEFAULT = LIST_ALL ^ LIST_UNIQUE; // (101)
Here, we have the LIST_ALL
flag that activates all the options. We then use the ^
operator to deactivate the unique option, leaving other options activated as required.
Now that we have the option flags ready, we can go ahead and define the normalizeList()
function:
function normalizeList (list, flag = LIST_DEFAULT) { if (flag & LIST_FRACTION) { const max = Math.max(...list); list = list.map(value => Number((value / max).toFixed(2))); } if (flag & LIST_UNIQUE) { list = [...new Set(list)]; } if (flag & LIST_SORTED) { list = list.sort((a, b) => a - b); } return list; }
To check if an option is activated, we use the &
operator to check if the corresponding bit of the option is turned on (set to 1
). The &
operation is carried out with the flag
argument passed to the function and the corresponding flag for the option, as demonstrated in the following code snippet:
// Checking if the unique option is activated // (flag & LIST_UNIQUE) === LIST_UNIQUE (activated) // (flag & LIST_UNIQUE) === 0 (deactivated) flag & LIST_UNIQUE
Here is a recap of the JavaScript Bitwise operators we covered in this article, their symbols, and what each of them does.
Operator
|
Symbol
|
Description
|
Bitwise NOT
|
~ |
|
Bitwise AND
|
& |
|
Bitwise OR
|
| |
|
Bitwise XOR
|
^ |
|
Left Shift
|
<< |
|
Sign-Propagating Right Shift
|
>> |
|
Zero-Fill Right Shift
|
>>> |
|
JavaScript bitwise operators, though sparingly used, have interesting use cases, as we’ve seen in this article. I strongly hope that the insights you’ve gotten in the course of reading this article will find expression in your day-to-day coding from now on. Happy coding!
Debugging code is always a tedious task. But the more you understand your errors, the easier it is to fix them.
LogRocket allows you to understand these errors in new and unique ways. Our frontend monitoring solution tracks user engagement with your JavaScript frontends to give you the ability to see exactly what the user did that led to an error.
LogRocket records console logs, page load times, stack traces, slow network requests/responses with headers + bodies, browser metadata, and custom logs. Understanding the impact of your JavaScript code will never be easier!
Would you be interested in joining LogRocket's developer community?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowLearn how to manage memory leaks in Rust, avoid unsafe behavior, and use tools like weak references to ensure efficient programs.
Bypass anti-bot measures in Node.js with curl-impersonate. Learn how it mimics browsers to overcome bot detection for web scraping.
Handle frontend data discrepancies with eventual consistency using WebSockets, Docker Compose, and practical code examples.
Efficient initializing is crucial to smooth-running websites. One way to optimize that process is through lazy initialization in Rust 1.80.
8 Replies to "A guide to JavaScript bitwise operators"
There’s a very handy trick that uses the & operator but has nothing to do with bitwise operations.
Let’s say you have unlined arrow functions, and thanks to e.g. prettier, they get formatted like this:
`window.addEventListener(‘click’, event => this.handleEvent(event))`
If you now quickly want to log the event, you can go like this:
`window.addEventListener(‘click’, event => console.log(event) & this.handleEvent(event))`
Using && here is not an option, as console.log doesn’t return anything truthy.
Rewriting to add curly brackets just to insert a second line for the console.log statement..just takes too long.
So what you can quickly do is prepend the log statement with a single `&` and both statements will be executed “in parallel”.
Of course this is only useful when dealing with side effects only and the return value of the inline function is not actually used.
Still i find it a useful trick to know.
Hello Jovica,
Nice use case you pointed out there. However, for cases like the one you mentioned above, I recommend using the Comma operator (`,`), which is what I normally use, like so:
`window.addEventListener(‘click’, event => (console.log(event), this.handleEvent(event)))`
The reason is because of the `&` operator will always return an integer while the `,` operator preserves the value of the last operand.
Here is a simple scenario, compare the returned values of these two functions:
FUNCTION 1:
`const stringifyAnd = data => console.log(data) & JSON.stringify(data);`
FUNCTION 2:
`const stringifyComma = data => (console.log(data), JSON.stringify(data));`
One piece not covered is bitwise shift, which is useful for setting flags in a clear way, for example.
const LIST_FRACTION = 1 << 0; // (001)
const LIST_UNIQUE = 1 << 1; // (010)
const LIST_SORTED = 1 << 2; // (100)
Beyond that, you don't need to check against the flag, since a match will be non-zero (truthy)
if (flag & LIST_UNIQUE) {}
Hi, Glad.
Nice article. Lots of good information.
Most of my programming is for discrete mathematics applications; I always have an eye open for ways to write more concise code and, ideally, programs that execute faster. If a built-in function, with its overhead, can be replaced by a simple bitwise operation, I tend to prefer the bitwise option.
Good to see you discussed the method for checking if an integer is odd:
if (value & 1)
Bitwise operators can also be used to floor or truncate a real number. For example, say you want to take just the integer part of a positive floating point number. You could do it several ways:
intVal = ~~floatVal;
intVal = floatVal | 0;
There are a few other ways to do it too. And keep in mind that if the numbers are negative, a check might have to be made first. BUT if you are working with positive numbers, this technique is good to keep in your back pocket for possible future use.
And bitwise operations can be used to swap two integer variables without the use of a third, temporary, variable. Again, sometimes handy.
One number manipulation technique I’d like to see: how to take the absolute value of a number by using bitwise operations. Any suggestion?
also you can use double bitwise NOT to round number ~~1.235 = 1
> `(2^32 – 1), which is 2147483647`
This is completely wrong. `(2^32 – 1)` is 4294967295. On the other hand 2147483647 equals to `(2^31 – 1)`.
Thanks a lot for the explanation
Thank You!
Your explanation on the usage of the ‘NOT’ and the ‘AND’ operators taught me what I needed to know.
JavaScript is not my first programming language (it’s around my 3rd/4th). I’ve recently been advancing my skills/knowledge, though. While doing so I recognized that I’d need a very concise way of changing a binary value.
W3Schools.com has a nice reference page, but it doesn’t explain why anyone would use bitwise operation.
This helps.
Thank You!