26

Exactly why does the condition here evaluate to true?

var condition = new Boolean(false);
if (condition == !condition)
    alert("The more you know...");
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
user541686
  • 189,354
  • 112
  • 476
  • 821
  • 2
    anyone noticed `condition === !condition` returning `false`. – Praveen Aug 06 '13 at 04:03
  • 1
    The `==` operator performs type coercion when comparing different types. You're comparing an object to a boolean. Read the algorithm used to coerce the types to matching types here: http://es5.github.io/#x11.9.3 –  Aug 06 '13 at 04:11
  • This should help settling things down: http://jsfiddle.net/acdcjunior/zKQ77/3/ – acdcjunior Aug 06 '13 at 04:12
  • 1
    @CrazyTrain acdcjunior Well said. Thank you so much for the link and fiddle. – Praveen Aug 06 '13 at 04:15
  • 1
    @acdcjunior: I don't get it, your JSFiddle just shows me the output. The question isn't *what* the output is, but *why*. – user541686 Aug 06 '13 at 04:18
  • 1
    @Mehrdad true (at least this one is for sure :), that's why I didn't post is as an answer. It should help because there is an assertion war going on, and that may show what the browser actually does. – acdcjunior Aug 06 '13 at 04:21
  • @acdcjunior: Ah I see, okay thanks. – user541686 Aug 06 '13 at 04:22

4 Answers4

24

Break it down:

var condition = new Boolean(false);

This is actually an object, and condition.valueOf() === false

!{} evaluates to false since {} is true (explained http://www.ecma-international.org/ecma-262/5.1/#sec-9.2)

So the check is condition.valueOf() == false, which is true

SheetJS
  • 20,261
  • 12
  • 60
  • 74
23

You're comparing an object (LHS) to the boolean false (RHS).

[object Boolean] == false

The == operator performs type coercion according to the Abstract Equality Comparison Algorithm defined by ECMAScript. 11.9.3 The Abstract Equality Comparison Algorithm

Relevant to your code is the following point of that algorithm (where x is the LHS and y is the RHS).

7) If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).

Notice that it actually first attempts to convert the boolean to a number. The false boolean converts to the number 0, so now we have this:

[object Boolean] == 0

As you can see, it recursively enters the same algorithm because of the ==. So now we're comparing an object to a number and so the following point applies:

9) If Type(x) is Object and Type(y) is either String or Number, return the result of the comparison ToPrimitive(x) == y.

So here it's now attempting to coerce the object to its primitive value. From 9.1 ToPrimitive, when called on an Object:

Object Return a default value for the Object. The default value of an object is retrieved by calling the [[DefaultValue]] internal method of the object, passing the optional hint PreferredType. The behaviour of the [[DefaultValue]] internal method is defined by this specification for all native ECMAScript objects in 8.12.8.

So you can see that it wants the [[DefaultValue]] of the object. That brings us to 8.12.8 [[DefaultValue]], where it expects a "hint". Because it received no "hint", it behaves as though the hint was "Number".

When the [[DefaultValue]] internal method of O is called with no hint, then it behaves as if the hint were Number,...

And so that brings us to the following behavior:

When the [[DefaultValue]] internal method of O is called with hint Number, the following steps are taken:

  1. Let valueOf be the result of calling the [[Get]] internal method of object O with argument "valueOf".

  2. If IsCallable(valueOf) is true then,

    a. Let val be the result of calling the [[Call]] internal method of valueOf, with O as the this value and an empty argument list.

    b. If val is a primitive value, return val.

And so it calls the .valueOf() method on the object, bringing us to 15.6.4.3 Boolean.prototype.valueOf ( )

  1. Let B be the this value.

  2. If Type(B) is Boolean, then let b be B.

  3. Else if Type(B) is Object and the value of the [[Class]] internal property of B is "Boolean", then let b be the value of the [[PrimitiveValue]] internal property of B.

  4. Else throw a TypeError exception.

  5. Return b.

And so you can see from step 3 that it will return the [[PrimitiveValue]] of the object. That brings us to 15.6.2.1 new Boolean (value)

The [[PrimitiveValue]] internal property of the newly constructed Boolean object is set to ToBoolean(value).

And so you can see that you'll finally get the ToBoolean value of the value you originally passed to the constructor, which was false. Its ToBoolean value is obviously false, so now your comparison is this:

false == 0

Since the types still don't match, it'll go to point 6 in the original algorithm:

6) If Type(x) is Boolean, return the result of the comparison ToNumber(x) == y.

And so it now wants to convert the boolean false to a number. This is similar to what was done above. The value false converts to the value 0, so now we have:

0 == 0

And finally we have a type matched comparison, and so it behaves the same as its strict === counterpart, by comparing values. And clearly, 0 does equal 0, so we get true.


Moral of the story... this is what you get when you ask "why" in JavaScript.

7

It really helps just to read the spec where this is logically laid out, see

Start with:

var x = new Boolean(false);
var y = !x;

Then

y = false;

Because a boolean object is not considered a boolean but an everday object, ToBoolean(x) evaluates to true and the !true evaluates to false

The Abstract Equality Comparison Algorithm

Round 1: step 7

If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).

y = 0; //ToNumber(false) is 0

Round 2: step 9

If Type(x) is Object and Type(y) is either String or Number, return the result of the comparison ToPrimitive(x) == y.

x = false //Basically ends up calling x.valueOf()

Round 3: Step 6

If Type(x) is Boolean, return the result of the comparison ToNumber(x) == y.

x = 0; //ToNumber(false) is 0

Finally: Step 1

If Type(x) is the same as Type(y), then

Step 1 C

If Type(x) is Number, then

Step 1 C iii

If x is the same Number value as y, return true.

Esailija
  • 130,716
  • 22
  • 250
  • 308
4

One thing I learned from The Abstract Equality Comparison Algorithm is, forget intuition, and follow the steps.

As objects are truthy, their negation is false, so what goes into the algorithm is:

Boolean(false) == false

If you go step by step, you get:

Boolean(false) == 0  // Step 7
false == 0           // Step 9
0 == 0               // Step 6
true
bfavaretto
  • 69,385
  • 15
  • 102
  • 145