Bitwise Truthiness

In this blog post, I explore another form of truthiness in Javascript. What happens if you use a bitwise operator on a value like 0|value or ~~value.

Context

We recently turned on the JSHint bitwise rule by default and the following code was caught.

var isValid = false;
for (var i = 0; i < elements.length; ++i) {
  isValid |= elements.someProperty;
}
return isValid;

The author didn't mean to use a bitwise operator and wanted to write the following instead:

  isValid = isValid || elements.someProperty;

Unfortunately, while the two lines look similar, they do not behave the same for all Javascript values. Instead of using the truthiness rules, the value is first converted to a signed 32bit integer and compared against 0.

Booleans and special values

In this system, booleans and special values are behaving as expected:

  • 0 | undefined === 0
  • 0 | null === 0
  • 0 | false === 0
  • 0 | true === 1

Numbers

It becomes a bit more tricky with numbers. The double is first converted to signed 32 bits integer and then compared to 0.

For usual integers, it is working as expected, only 0 is falsy.

  • 0 | 0 === 0
  • 0 | 1 === 1
  • 0 | 42 === 42
  • 0 | -1 === -1

NaN (not a number) is considered as falsy, still going as expected.

  • 0 | NaN === 0

For non integers, it is more tricky. Any number in the range ]-1, 1[ is going to be falsy. Lines highlighted in yellow do not behave the same as normal truthy values.

  • 0 | 0.99 === 0
  • 0 | -0.99 === 0
  • 0 | 1.01 === 1

For big integers, the situation is even more confusing. They are all truthy except multiples of 232. This is true even after 253.

  • 0 | Math.pow(2, 32) === 0
  • 0 | 3 * Math.pow(2, 32) === 0
  • 0 | Math.pow(2, 53) === 0
  • 0 | Math.pow(2, 60) === 0
  • 0 | Math.pow(2, 32) + 1 === 1

Strings

Contrary to normal truthiness, strings in general are falsy.

  • 0 | "" === 0
  • 0 | " " === 0
  • 0 | "a" === 0

But, strings that represent numbers now follow number rules.

  • 0 | "0" === 0
  • 0 | "1" === 1
  • 0 | "0.5" === 0

The number parser is not rigid and accept inputs that have whitespace around for example.

  • 0 | "    1    " === 1

Objects

Objects are first converted to string before being converted to int32. So nearly all objects are falsy because their string representation is "[object Object]".

  • 0 | {} === 0
  • 0 | {key: 1} === 0

You can still craft objects that passes that check by overriding toString.

  • 0 | {toString: function() { return "1"; }} === 1

Conclusion

The normal truthiness rules can be quite misleading, but if you want to shoot yourself in the foot, I highly encourage you to replace all your !!expression into 0|expression. This will give you endless hours of debugging fun.

If you liked this article, you might be interested in my Twitter feed as well.
 
 

Related Posts

  • August 23, 2011 Javascript – Hook Technique (5)
    Let's go back 5 years ago during the World of Warcraft beta. I was working on Cosmos UI, a projects that aimed to improve the World of Warcraft interface. As interface modification was not officially supported by Blizzard, we went ahead and directly modify the game files written in […]
  • September 17, 2011 WoW Interface Anchor Positioning (6)
    I've always found CSS positioning with both float and position: absolute/relative hard to work with. I want to introduce to you an alternative way borrowed from the World of Warcraft Interface: Anchors. Anchor The concept is extremely simple. You can tell where you want the element […]
  • August 27, 2011 Start a technical blog, it’s worth it! (4)
    Lately, I've been advocating to all my student friends to start a blog. Here's an article with the most common questions answered :) What are the benefits? Being known as an expert. The majority of my blog posts are about advanced Javascript topics. As a result, I'm being tagged as […]
  • October 26, 2011 Javascript Presentation – Slides & Video (2)
    I've done the Javascript presentation. It went alright and I hope that I taught things to people. I'm sorry for my blog reader but it's in French :) Few remarks: The code in the slide was not big enough, people in the back couldn't read it. It also appears crappy in the […]
  • October 12, 2011 Intercept and alter <script> include (2)
    For a project, I want to transparently be able to intercept all the included javascript files, edit the AST and eval it. This way I can manipulate all the code of an application just by inserting a custom script. Hook the <script> tag insertion. Download the Javascript file […]