There is a huge difference between a Boolean object and a Boolean primitive. The MDN page you referenced, actually warns about this at the very outset:
Do not confuse the primitive Boolean
values true
and false
with the true
and false
values of the Boolean
object.
Any object, including a Boolean
object whose value is false
, evaluates to true
when passed to a conditional statement.
And this (what I marked in bold) is exactly what happens in your code: it creates a new Boolean(false)
and that will coerce to true
-- in other words it is a truthy value. In your code you have explicitly converted it to a boolean primitive, by applying !
to it twice. In either case (implicit coercion or explicit conversion) new Boolean(false)
is truthy. Fact is that all objects are considered truthy (when coerced to boolean, they evaluate to true
).
The article continues with:
Do not use the Boolean()
constructor with new to convert a non-boolean value to a boolean value — use Boolean
as a function or a double NOT instead.
This suggests that your code should be modified to drop the use of new
, and call Boolean
as a plain function, not as constructor:
!!(Boolean(false)) === false
When Boolean
is called as plain function, it returns a primitive boolean (false
or true
). But anything that is called as constructor, even Boolean
, will return an object. And objects are truthy.
When in the context of coercion MDN states "Booleans are returned as-is." they refer to boolean primitives. (Boolean) objects are covered by the last bullet point in the same list: "All objects become true
". The latter in includes Boolean
objects.
A Boolean
object has a valueOf
method which returns a boolean primitive, and so it returns what you would intuitively expect.
The MDN article rightly says:
Warning: You should rarely find yourself using Boolean
as a constructor.
Don't use new Boolean
, but Boolean
.
If for some reason you have a Boolean
object, really ask yourself why you have that object in the first place. Tackle the code that created that object and use a primitive boolean from the outset.
Objects are truthy
Some are surprised in a similar way that the following holds:
if (!!new String("")) console.log("An empty string is truthy!?");
if (!!new Number(0)) console.log("The number 0 is truthy!?");
if (!!new Number(NaN)) console.log("NaN is truthy!?");
if (!!new Object(null)) console.log("null is truthy!?");
if (!!new Object(undefined)) console.log("Undefined is truthy!?");
It is the same principle: objects are truthy. Always.* No matter what their constructor is named. No matter what value was passed to that constructor.
* document.all
is an abhorrent, but accepted, violation of this rule.
See also