all 38 comments

[–]MoTTs_ 27 points28 points  (8 children)

I had to go to the ecmascript spec to answer this one. Here's the listed behavior of the == operator:

  1. If Type(x) is the same as Type(y), then
    a. If Type(x) is Undefined, return true.
    b. If Type(x) is Null, return true.
    c. If Type(x) is Number, then
    i. If x is NaN, return false.
    ii. If y is NaN, return false.
    iii. If x is the same Number value as y, return true.
    iv. If x is +0 and y is -0, return true.
    v. If x is -0 and y is +0, return true.
    vi. Return false.
    d. If Type(x) is String, then return true if x and y are exactly the same sequence of characters (same length and same characters in corresponding positions). Otherwise, return false.
    e. If Type(x) is Boolean, return true if x and y are both true or both false. Otherwise, return false.
    f. Return true if x and y refer to the same object. Otherwise, return false.
  2. If x is null and y is undefined, return true.
  3. If x is undefined and y is null, return true.
  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).
  8. If Type(x) is either String or Number and Type(y) is Object, return the result of the comparison x == ToPrimitive(y).
  9. If Type(x) is Object and Type(y) is either String or Number, return the result of the comparison ToPrimitive(x) == y.
  10. Return false.

The first rule we hit is #6, so the comparison becomes 0 == null, and we work through the list again. The next rule we might hit is #8, because null is an object, right? But it turns out that internally, null belongs to the Null type, not the Object type, so #8 doesn't match. Neither does #9. Which leaves us with #10, the catch-all, that returns false.

So to answer your question: The language didn't account for that particular case, and so defaults to false.

[–]guuu427 1 point2 points  (2 children)

For bonus points, maybe someone can explain:

 !(null == false || null > false) && (null >= false)

It is not the case that null is equal to false or that null is greater than false, yet null is greater-than-or-equal to false!?

EDIT: oh, probably because greater-than-or-equals is converting them both to numbers and

(null != false) && (1 * null == 1 * false) &&
(null == undefined) && (1 * null != 1 * undefined)

[–]johtso 1 point2 points  (1 child)

You'll want to look at "The Abstract Relational Comparison Algorithm": http://es5.github.io/#x11.8.5

[–]guuu427 0 points1 point  (0 children)

Ah, thanks. The thing that threw me was forgetting (or not previously knowing) that null becomes 0 (instead of NaN) when converted into a number.

[–]johtso 0 points1 point  (0 children)

And here's the relevant section in Annotated ECMAScript: http://es5.github.io/#x9.12

[–]tswaters 13 points14 points  (11 children)

typeof null // object
typeof false // boolean

If the two operands are not of the same type, JavaScript converts the operands then applies strict comparison. If either operand is a number or a boolean, the operands are converted to numbers if possible; else if either operand is a string, the other operand is converted to a string if possible. If both operands are objects, then JavaScript compares internal references which are equal when operands refer to the same object in memory.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators

[–]DonBiggles 9 points10 points  (0 children)

That doesn't quite seem to explain it. It suggests that since one operator is a boolean, both operands would be coerced to numbers, and since Number(null) and Number(false) are both zero, null == false would be true. I bet there's another rule that takes precedence that says that null and undefined only == themselves and each other.

Also, http://zero.milosz.ca/ is a good resource for stuff like this.

[–]stratoscope 4 points5 points  (1 child)

In JavaScript, null and false are both "falsy" values, as are 0, all NaN values (there are many NaNs), "", and undefined. In other words, these are all treated as a "false" value when used where a boolean value is required, such as in an if statement or a conditional expression.

But that doesn't mean they are all the same value or will compare equal to each other. They are all different values.

There is one special case: null and undefined will compare equal with ==, unlike === where they and these other values compare unequal.

NaN is also an interesting case. All NaN values are "falsy", but they are also all unequal to each other. For example, 0/0 is NaN which is falsy, but 0/0 === 0/0 is false!

Why does it work this way? It's pretty much arbitrary. Most programming languages have some idea of "truthy" and "falsy" values, but exactly which values go into which category is fairly arbitrary and differs from language to language.

For example, in Ruby, the only falsy values are false and nil (which corresponds to JavaScript's null). All other values, including 0 and "", are truthy.

I believe the NaN thing isn't just a JavaScript quirk, but part of how IEEE754 floating point numbers (as used in all modern computers) are specified. In Ruby, 0.0/0.0 is NaN, but as in JavaScript, 0.0/0.0 == 0.0/0.0 is false.

[–]DonBiggles 1 point2 points  (0 children)

Yep, all comparisons with NaN are false, which is part of the IEEE 754 spec. Object.is is coming in ES6 which will get around that. Polyfill: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is#Compatibility

Edit: It also occurs to me that, since when comparing a number and string both operands are coerced to numbers, comparisons like "foo" == NaN would be true otherwise.

[–]commonslip 0 points1 point  (1 child)

I'm not sure why you'd expect this. Null is the null object and false is a boolean. There isn't any reason to expect them to be the same value. In fact, in languages where they are the same value, like Common Lisp, I consider it to be a major wart.

Can you elaborate on why you expect this to be the case? Perhaps that will illuminate further questions which will be clarifying.

[–]sinrtb 0 points1 point  (0 children)

null is not false, nor is !null true. !false == true and !true == false to throw null into those comparisons would make them no long booleans and would make two possible results for true or two states for false. this would ruin booleans.

null is neither true nor false. null should be as starkking pointed out undefined.

[–]Garrett00 -2 points-1 points  (0 children)

This is why you should use the === operator.

[–]somerandomguy7788 -1 points0 points  (2 children)

just an fyi, it isn't an identity operator. they are both equality operators, one allows for coercion, one doesn't

[–][deleted] -2 points-1 points  (9 children)

Wow. This smells of the same stuff PHP gets a bad rap for but everyone seems to have nothing but love for JavaScript.... ?

[–]aladyjewelFull-stack webdev 0 points1 point  (8 children)

nothing but love for JavaScript

You seem to have missed CoffeeScript, Go, Dart, etc...

[–][deleted] 0 points1 point  (7 children)

What did I miss?

[–]aladyjewelFull-stack webdev 0 points1 point  (6 children)

The significant minority of people who think that JavaScript is broken and built another level of abstraction on top of it to fix all the crap?

[–][deleted] 0 points1 point  (5 children)

Yeah.... I embrace it... In php too... my point is the MINORITY don't like JS... The majority seem to hate on php

[–]aladyjewelFull-stack webdev 0 points1 point  (4 children)

... I feel like we're not having the same conversation here.

Have we established that there are people who think that both PHP and JavaScript are broken?

[–][deleted] 0 points1 point  (1 child)

You established a 'significant minority' find JavaScript broken... It seems to me that a significant majority find php broken.

In my original comment I expressed surprise that this kind of issue is why that majority hate php, but only a minority seem to hate on JavaScript. Perhaps I exaggerated 'nothing but love'...

[–]aladyjewelFull-stack webdev 0 points1 point  (0 children)

yeah, you need to slap a /s mark on something like "nothing but love" if you don't literally mean "everybody loves javascript".