0

I am wondering why the Boolean coercion fails in this case:

!!(new Boolean(false)) === true

Although:

(new Boolean(false).valueOf())  === false

Mozilla says:

Booleans are returned as-is.

I am wondering what "as-is" means in the context of a coercion. I thought "coercion" means "convert anything to a primitive boolean". How is it possible that something which is meant to be false gets coerced to true?

BTW: Consequently this fails too:

Boolean(new Boolean(false)) === true
ceving
  • 21,900
  • 13
  • 104
  • 178

2 Answers2

0

It seems to me, that the Boolean class itself is an error. Maybe I have to use the following code:

if (arg instanceof Boolean)
    throw new Error("Stop doing nonsense")

Or maybe this:

function coerce_boolean_correctly (arg) {
  if (arg instanceof Boolean)
    return coerce_boolean_correctly(arg.valueOf())
  return !!arg
}
ceving
  • 21,900
  • 13
  • 104
  • 178
0

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

trincot
  • 317,000
  • 35
  • 244
  • 286
  • The advise "do not use `new Boolean`" is no solution. In particular it is no solution for library code. The class `Boolean` should be removed from the language, because it is nonsense. It is nonsense to create a Boolean class, when all instances of this class are always true. This is totally misleading. – ceving Feb 11 '23 at 12:40
  • Which library code are you referring to? – trincot Feb 11 '23 at 12:41