Understanding Javascript's Boolean object constructor

I came across an interesting behaviour recently when working with the Boolean global object constructor in Javascript. It took me a bit of reading to understand why my code wasn't behaving the way I expected, so I thought it was worth delving a bit deeper. Hopefully this will help you too.

Looking at the following code, you might be able to guess what it does.

let x = new Boolean(true);
x === true; // x is true

Makes sense, right?

But if you set the value to false on line 1, you get some... interesting results.

let x = new Boolean(false);
x === true; // x is still true!

Using x in a conditional reveals that it's true, even though we passed in false. So, what's going on here?

The Boolean primitive type

Javascript has 6 primitive types:

  • undefined
  • Boolean
  • Number
  • String
  • BigInt
  • Symbol

Boolean, the Javascript primitive type, can only ever have one of 2 values, true or false

In Javascript, values can either be 'truthy' or 'falsey'.

falsey values include:

  • undefined
  • Null
  • NaN
  • 0
  • "" (an empty string)
  • false

Any other value is considered truthy.

Both truthy and falsey values can be converted to a Boolean (either true or false) in a couple of different ways.

Option 1: The Boolean object constructor

const a = ''; // an empty string, falsey 
const bool = new Boolean(a);

This method uses the Boolean object constructor. As a is a falsey value; it's converted to false via type coercion.

This would be the equivalent of:

const bool = new Boolean(false);

If we now use the above in a conditional, eg. checking if it's true with the strict equality operator ====

bool === true; // true

it evaluates to true.

The reason why is that bool is not actually a Javascript Boolean primitive type in this instance, but a Boolean object.

🤯

What's the difference?

Where a Boolean primitive can simply be true or false, a Boolean object is an object wrapper around a boolean value.

A Boolean object provides some extra methods for working with Boolean values:

const bool = new Boolean(false);
bool === true; // true

bool.valueOf(); // false
bool.toString(); // 'false' (string)

So, to access the boolean value using the Boolean object constructor, we need to use .valueOf()

This is also why a conditional on a Boolean object will always return true.

const bool = new Boolean(false);
bool === true; // true

This is because the value of bool is not true, but an object with methods on it's prototype.

__proto__: Boolean
  constructor: f Boolean()
  toString: f toString()
  valueOf: f valueOf()

As this is an object, any conditional on it will always be true, as objects are always truthy

So, how should we convert a value to a Boolean primitive value?

All of the above makes using the new Boolean object constructor a bit ...confusing. It's not exactly what you'd expect it to do when reading the code, and I can understand why people (including myself) could get confused why new Boolean(false) equals true.

For this reason, it might be a good idea to steer clear of using the Boolean object constructor altogether. Our alternatives include:

Option 2: The global function Boolean()

JS also has a global function available named Boolean()

So you can do:

const bool = Boolean(false);
bool === true; false

This is what we would expect. We can check the type of our value with typeof

typeof bool; // Boolean

The Boolean function and the Boolean object constructor are very close in syntax. They're pretty much exactly the same, except one has the new operator

const booleanPrimitive = Boolean(true);
const booleanObject = new Boolean(true);

typeof booleanPrimitive; // boolean
typeof booleanObject; // object

Personally, I think the syntax is a little too close. It can make it a little hard to remember. Luckily, there is another option, which provides it's own benefits.

Option 2: The double not (!!) operator

The not operator in Javascript is denoted by a ! (exclamation mark, also known as a bang).

The ! is used to negate a value, eg.

const condition = false;

if (!condition) {
  // this code will run
}

So, if ! negates a value, then using 2 of them negates the value, and converts it to a boolean value.

eg.

const string = 'blue';
const bool = !!string; // true

typeof bool; // Boolean

Double bangs will convert any truthy value to true, and any falsey value to false.

!!undefined; // false
!!''; // false
!!'a great day'; // true
!!10; // true
!!{a:1, b:2}; // true, because objects are truthy

The double not / double bang operator has a couple of advantages here. It's terse: !! is a lot shorter that Boolean(value) or new Boolean(value) (and then checking the value with .valueOf()).

It also avoids having to remember the difference bewteen Boolean() and new Boolean().

The cons are that it is syntactically a bit harder to understand what's going on. For this reason, using the Boolean() global function may be easier to read.

In conclusion

new Boolean(false)

The Boolean object wrapper may not do what you think. The above code doesn't evaluate to false in a conditional. You can achieve the same affect with the global Boolean() function (with syntax so similar it can make it a little hard to remember..) or by using the !! (double not operator).

I'd be interested to see what kind of best practices people use in their codebases.

eslint Actually has a rule that disallows creating the Boolean object wrapper (along with the String and Number wrapper). It looks like this rule is available to avoid the kind of errors that we have looked at in detail here.

How do you approach this kind of thing when your creating Booleans in Javascript?

References:

MDN: Boolean object constructor

James Padolsey: Truthy & Falsey

Free Code Camp: Javascript type coercion explained