Rationale for why ECMAScript converts primitive values to numbers in == operator comparisons when one is boolean

Brendan Eich brendan at mozilla.com
Sun Jan 6 14:52:33 PST 2013


Raymond Plante wrote:
> Just curious to find out what the motivation for converting both 
> values of an == operation to integers if one is an integer or a boolean.
>
> This situation allows for:
>    if ("true"){}  // to evaluate to true
>    if("true" == true){} // to evaluate to false as it's really 
> checking if( NaN == 1){}

Consider Perl:

$ perl -e 'print 0 == "true";'
1

Ok, poor rationale -- but I created JS in May 1995, in the shadow of 
AWK, Perl 4, Python 1.2 (IIRC), TCL.

I should have paid more attention to AWK than Perl, given

$ awk 'END {print(0 == "0")}'
1D
$ awk 'END {print(0 == "")}'
0D

In some ways, JS's == operator splits the difference between Perl (where 
non-numeric strings such as "true" convert to 0) and AWK (where only "0" 
converts to 0) by converting to NaN. That way, at least, we have

js> 0 == ""
true
js> 0 == "true"
false

But the full truth is not that I was carefully emulating other 
languages. Rather, some Netscapers working to embed JS (then "Mocha") in 
a PHP-like server (LiveWire) wanted sloppy conversions, so programmers 
could match HTTP header strings (server side) or HTML form fields 
(client side) against, e.g., 404 and the like, without explicit coercion 
by the programmer.

But it was the 90s, I was in a tearing hurry, these ex-Borland 
Netscapers were persistent. So, as I said at Strange Loop last year 
(http://www.infoq.com/presentations/State-JavaScript), "I was an idiot! 
I gave them what they wanted!"

Implicit conversions are my biggest regret in JS's rushed design, bar 
none. Even including 'with'!

> Does anyone know the exact reason the choice was made not to convert 
> to boolean any value compared against a boolean in with the == operator?
The general idea is the narrower type should widen. Thus, true == 1 
follows by projecting boolean {false, true} onto {0, 1}, as in C++.

But why not widen true to string, since the other operand in your 
example is "true"? Good question. The bias toward comparing strings as 
numbers if either operand is a number or a boolean stems from the HTTP 
header and numeric-string HTML form field use-cases. Not good reasons, 
again, but that's how JS "works" :-|.

You can see this in the ECMA-262 Edition 5.1 spec, 11.9.3 The Abstract 
Equality Comparison Algorithm, steps 6 & 7 (read in light of steps 4 & 5):

4. If Type(x) is Number and Type(y) is String, return the result of the 
comparison x == ToNumber(y).
5. If Type(x) is String and Type(y) is Number, return the result of the 
comparison ToNumber(x) == y.
6. If Type(x) is Boolean, return the result of the comparison 
ToNumber(x) == y.
7. If Type(y) is Boolean, return the result of the comparison x == 
ToNumber(y).

This is all in a big "else clause where Type(x) and Type(y) for x == y 
are not the same.

Sorry there's no pearl (sic) of wisdom here. In addition to implicit 
conversions, == and != do not widen operands directly (no intermediate 
conversions) to the narrowest width that can hold the other operand 
without data loss. This narrowing string to number is just a botch.

If we fixed this botch, we'd still have:

0 == "0"
true == "1"
false == "0"

But we would also have what your example wants:

true == "true"

Some take this botch, on top of any implicit conversion under the hood, 
as another reason to use === and !== always (because they never 
convert), and to utterly shun == and !=. Others disagree (especially 
when testing x == null, a one-operator way to test x === null || x === 
undefined).

Since the web grows mostly-compatibly until very old forms die off, 
we're stuck with == and !=, so I say it pays to learn what the sloppy 
equality operators do. Having done that, it seems to me one may use them 
where they win: when you know the operands are same-type, e.g.

typeof x == "function", etc.
x == null

And otherwise, use === and !==.

/be


More information about the es-discuss mailing list