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