DEV Community

Cover image for How to use the bitwise XOR (^) operator in JavaScript
Muhammad Sifat Hossain
Muhammad Sifat Hossain

Posted on

How to use the bitwise XOR (^) operator in JavaScript

Currently, I'm working on a Pomodoro timer application where I have an entity
called project-category. It has the following interface:

interface ProjectCategory {
  name: string;
  createdOn: number;
  modifiedOn: number;

  // ... some other fields
}
Enter fullscreen mode Exit fullscreen mode

I've written a function that validates and instantiates a project category
object. In regards to the timestamp validation, I have implemented these rules:

  1. If both the creation and modification timestamps are absent, assign them the
    current timestamp.

  2. If both the creation and modification timestamps are present, then make sure:
    that the modification timestamp is greater than or equal to the creation
    timestamp.

  3. Otherwise, throw an error.

And the code looks something like this:

function makeProjectCategory( arg: Partial<ProjectCategory>): Readonly<ProjectCategory> {
  const projectCategory: Partial<ProjectCategory> = {};
  // ... timestamps validation

  {
    const isCreatedOnPresent = "createdOn" in arg;
    const isModifiedOnPresent = "modifiedOn" in arg;

    const isOneTimestampMissing = +isCreatedOnPresent ^ +isModifiedOnPresent;
    // (isCreatedOnPresent && !isModifiedOnPresent) ||
    // (!isCreatedOnPresent && isModifiedOnPresent);

    if (isOneTimestampMissing)
      throw new Error(
        `Creation and Modification timestamps must be provided together.`
      );

    if (isCreatedOnPresent) {
      // so both timestamps are present
      assertValidTimestamps({
        createdOn: arg.createdOn,
        modifiedOn: arg.modifiedOn,
      });
      // ...
    } else projectCategory.createdOn = projectCategory.modifiedOn = Date.now();
  }

  // ... other fields validation

  return Object.freeze(projectCategory) as Readonly<ProjectCategory>;
}
Enter fullscreen mode Exit fullscreen mode

After writing this code, I realized that the validation logic is similar to an
XOR logic gate.

isCreatedOnPresent isModifiedOnPresent isOneTimestampMissing (should throw ?)
true true false
false true true
true false true
false false false

So changed the following snippet

const isOneTimestampMissing =
  (isCreatedOnPresent && !isModifiedOnPresent) ||
  (!isCreatedOnPresent && isModifiedOnPresent);
Enter fullscreen mode Exit fullscreen mode

to:

const isOneTimestampMissing = +isCreatedOnPresent ^ +isModifiedOnPresent;
Enter fullscreen mode Exit fullscreen mode

Let me explain how it works.

Truth table of XOR logic gate

Input Bit A Input Bit B Resulting Bit
1 1 0
1 0 1
0 1 1
0 0 0

If the XOR operator (^ in JS) is applied on two bits, it returns:

  • 1 (true) if they are alternating.
  • 0 (false) if they are the same.

So if you run the following snippet, you'll see:

console.log(1 ^ 1); // 0
console.log(1 ^ 0); // 1
console.log(0 ^ 1); // 1
console.log(0 ^ 0); // 0
Enter fullscreen mode Exit fullscreen mode

But wait, in the above code snippet 1 and 0 doesn't represent a single bit!
Strictly speaking it's a 32 bit number. When the XOR operator is applied on two
numbers, first it converts the numbers to a binary form and then operates on
each bit at a time. Let me illustrate.

#1:  1 ^ 1 = 0

1: 00000000000000000000000000000001
1: 00000000000000000000000000000001
-----------------------------------
0: 00000000000000000000000000000000

#2:  12 ^ 15 = 3

12: 00000000000000000000000000001100
15: 00000000000000000000000000001111
------------------------------------
 3: 00000000000000000000000000000011
Enter fullscreen mode Exit fullscreen mode

Again, how does this (+isCreatedOnPresent ^ +isModifiedOnPresent) code
work? The + in front of two variables is called the Unary Plus Operator.
It coerces a value to number. So, +isCreatedOnPresent is exactly similar to
Number(isCreatedOnPresent). And as these two variables are of type boolean;
they are coerced to either 1 or 0. Because in JavaScript:

Number(true); // 1
Number(false); // 0
Enter fullscreen mode Exit fullscreen mode

Now, for example let's say, modifiedOn is present in the arg but
modifiedOn is not. This is how the code will be evaluated:

// isCreatedOnPresent = true, and isModifiedOnPresent = false
const isOneTimestampMissing = +isCreatedOnPresent ^ +isModifiedOnPresent;
                         // = +true ^ +false;
                         // = 1 ^ 0;
                         // = 1;

if (isOneTimestampMissing)
  // if (1)
  throw Error()

// as 1 is a truthy value the error will be thrown
Enter fullscreen mode Exit fullscreen mode

Conclusion

Honestly, I think it's not a good idea use the XOR (^) operator in my code
just to reduce one line. Because for the sake of brevity it sacrifices
readability and can confuse someone who does not know about the XOR
operator. But, I found a real life use case of it and just wanted to share it
with you guys šŸ˜€.

Credits

The cover image (XOR Gate in Minecraft) is taken from Imgur .

Top comments (1)

Collapse
 
maksymzav profile image
maksymzav

thanks, was really interesting to read)