Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

In JavaScript, the Good Parts, Douglas Crockford wrote:

JavaScript has two sets of equality operators: === and !==, and their evil twins == and !=. The good ones work the way you would expect. If the two operands are of the same type and have the same value, then === produces true and !== produces false. The evil twins do the right thing when the operands are of the same type, but if they are of different types, they attempt to coerce the values. The rules by which they do that are complicated and unmemorable. These are some of the interesting cases:

'' == '0'           // false
0 == ''             // true
0 == '0'            // true

false == 'false'    // false
false == '0'        // true

false == undefined  // false
false == null       // false
null == undefined   // true

' \t\r\n ' == 0     // true

The lack of transitivity is alarming. My advice is to never use the evil twins. Instead, always use === and !==. All of the comparisons just shown produce false with the === operator.

Given this unequivocal observation, is there ever a time when using == might actually be appropriate?

share|improve this question
8  
It makes sense in lots of places. Any time it's obvious you're comparing two things of the same type (this happens a lot in my experience), == vs === just comes down to preference. Other times you actually want abstract comparison (like the case you mention in your answer). Whether it's appropriate depends on conventions for any given project. –  Hey Jan 6 at 2:09
4  
Regarding "lots of places," in my experience the cases where it doesn't matter outnumber cases where it does. Your experience may be different; maybe we have experience with different kinds of projects. When I look at projects that use == by default, === stands out and lets me know something important is going on. –  Hey Jan 6 at 6:28
3  
I don't think JavaScript goes far enough with it's type coercion. It should have even more type coercion options, just like the BS language. –  Mark Booth Jan 6 at 14:18
4  
One place I use == is when comparing dropdown id's (which are always char) to model id's (which are commonly int). –  Scottie Jan 6 at 15:22
9  
@DevSolar Web development makes sense when you don't want to have to deal with producing a native app for each of 15 platforms as well as certification on the monopoly App Store of each platform that has one. –  tepples 2 days ago

6 Answers 6

up vote 160 down vote accepted

I'm going to make an argument for ==

Douglas Crockford which you cited is known for his many and often very useful opinions. While I'm with Crockford in this particular case it's worth mentioning it is not the only opinion. There are others like language creator Brendan Eich who don't see the big problem with ==. The argument goes a little like the following:

JavaScript is a behaviorally* typed language. Things are treated based on what they can do and not their actual type. This is why you can call an array's .map method on a NodeList or on a jQuery selection set. It's also why you can do 3 - "5" and get something meaningful back - because "5" can act like a number.

When you perform a == equality you are comparing the contents of a variable rather than its type. Here are some cases where this is useful:

  • Reading a number from the user - read the .value of an input element in the DOM? No problem! You don't have to start casting it or worrying about its type - you can == it right away to numbers and get something meaningful back.
  • Need to check for the "existence" of a declared variable? - you can == null it since behaviorally null represents there is nothing there and undefined doesn't have anything there either.
  • Need to check if you got meaningful input from a user? - check if the input is false with the == argument, it will treat cases the user has entered nothing or just white-space for you which is probably what you need.

Let's look at Crockford's examples and explain them behaviorally:

'' == '0'           // got input from user vs. didn't get input - so false
0 == ''             // number representing empty and string representing empty - so true
0 == '0'            // these both behave as the number 0 when added to numbers - so true    
false == 'false'    // false vs got input from user which is truthy - so false
false == '0'        // both can substitute for 0 as numbers - so again true

false == undefined  // having nothing is not the same as having a false value - so false
false == null       // having empty is not the same as having a false value - so false
null == undefined   // both don't represent a value - so true

' \t\r\n ' == 0     // didn't get meaningful input from user vs falsey number - true 

Basically, == is designed to work based on how primitives behave in JavaScript not based on what they are. While I don't personally agree with this point of view there is definitely merit in doing it - especially if you take this paradigm of treating types based on behavior language-wide.

* some might prefer the name structural typing which is more common but there is a difference - not really interested in discussing the difference here.

share|improve this answer
7  
This is a great answer, and I use all three of your 'for ==' use cases. #1 & #3 are especially useful. –  Chris Cirefice Jan 6 at 7:06
125  
The problem with == isn't that none of its comparisons are useful, it's that the rules are impossible to remember so you are nearly guaranteed to make mistakes. For example: "Need to check if you got meaningful input from a user?", but '0' is a meaningful input and '0'==false is true. If you had used === you would have had to explicitly think about that and you wouldn't have made the mistake. –  Timmmm Jan 6 at 12:03
22  
"the rules are impossible to remember" <== this is the one thing that scares me away from doing anything "meaningful" in Javascript. (and float math that lead to problems in basic calc excercises) –  WernerCD Jan 6 at 14:37
8  
The 3 - "5" example raises a good point on its own: even if you exclusively use === for comparison, that's just the way variables work in Javascript. There's no way to escape it completely. –  Jarett Millard Jan 6 at 14:56
14  
@Timmmm note I am playing devil's advocate here. I don't use == in my own code, I find it an anti-pattern and I completely agree the abstract equality algorithm is hard to remember. What I'm doing here is making the argument people make for it. –  Benjamin Gruenbaum Jan 6 at 14:59

It turns out that jQuery uses the construct

if (someObj == null) {
  // do something
}

extensively, as a shorthand for the equivalent code:

if ((someObj === undefined) || (someObj === null))  {
  // do something
}

This is a consequence of the ECMAScript Language Specification § 11.9.3, The Abstract Equality Comparison Algorithm, which states, among other things, that

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.

and

2.  If x is null and y is undefined, return true.
3.  If x is undefined and y is null, return true.

This particular technique is common enough that JSHint has a flag specifically designed for it.

share|improve this answer
6  
No fair answering your own question I wanted to answer this :) == null or undefined is the only place where I don't use === or !== –  pllee Jan 5 at 22:40
18  
To be fair jQuery is hardly a model codebase. Having read the jQuery source several times it's one of my least favorite codebases with a lot of nested ternaries, unclear bits, nesting and things I would otherwise avoid in real code. Don't take my word for it though - read it github.com/jquery/jquery/tree/master/src and then compare it with Zepto which is a jQuery clone: github.com/madrobby/zepto/tree/master/src –  Benjamin Gruenbaum Jan 6 at 7:18
3  
Also note that Zepto seems to default to == and only uses === in cases where it's needed: github.com/madrobby/zepto/blob/master/src/event.js –  Hey Jan 6 at 7:24
1  
@Hey to be fair Zepto is hardly a model codebase either - it's infamous for using __proto__ and in turn forcing it almost single handedly into the language specification to avoid breaking mobile websites. –  Benjamin Gruenbaum Jan 6 at 9:07
2  
@BenjaminGruenbaum that wasn't a judgement call on the quality of their codebase, just pointing out that different projects follow different conventions. –  Hey 2 days ago

Checking values for null or undefined is one thing, as has been explained abundantly.

There's another thing, where == shines:

You can define comparison from >= like so (people usually start from > but I find this more elegant):

  • a > b <=> a >= b && !(b >= a)
  • a == b <=> a >= b && b >= a
  • a < b and a <= b are left as an exercise to the reader.

As we know, in JavaScript "3" >= 3 and "3" <= 3, from which you get 3 == "3". You can make a point that it's a horrible idea to allow implementing comparison between strings and numbers by parsing the string. But given that this is the way it works, == is absolutely the correct way to implement that relationship operator.

So the really good thing about == is that it is consistent with all other relationships. To put it differently, if you write this:

function compare(a, b) {
  if (a > b) return 1;
  if (a < b) return -1;
  return 0;
}

You are implicitly using == already.

Now to the quite related question of: Was it a bad choice to implement number and string comparison the way it is implemented? Seen in isolation, it seems a rather stupid thing to do. But in the context of other parts of JavaScript and the DOM, it's relatively pragmatic, considering that:

  • attributes are always strings
  • keys are always strings (the use case being that you use an Object to have a sparse map from ints to values)
  • user input and form control values are always strings (even if the source matches input[type=number])

For a whole number of reasons it made sense to make strings behave like numbers when needed. And assuming that string comparison and string concatenation had different operators (e.g. :: for concating and a method for comparing (where you can use all kinds of parameters regarding case sensitivity and what not)), this would in fact be less of a mess. But this operator overloading is probably in fact where the "Java" in "JavaScript" comes from ;)

share|improve this answer
3  
To be fair >= is not really transitive. It's quite possible in JS that neither a > b nor a < b nor b == a (for example: NaN). –  Benjamin Gruenbaum 2 days ago
3  
@BenjaminGruenbaum: That's like saying + is not really commutative, because NaN + 5 == NaN + 5 doesn't hold. The point is that >= works with number-ish values for which == works consistently. It shouldn't be surprising that "not a number" is by its very nature not number-ish ;) –  back2dos 2 days ago
3  
So the poor behavior of == is consistent with the poor behavior of >= ? Great, now I wish there was a >==... –  Eldritch Conundrum 2 days ago
1  
@EldritchConundrum: As I have tried to explain, the behavior of >= is rather consistent with the rest of the language/standard APIs. In its totality, JavaScript manages to be more than the sum of it's quirky parts. If you'd like a >==, would you also want a strict +? In practice, many of these decisions make many things a lot easier. So I wouldn't rush to judging them as poor. –  back2dos 2 days ago
2  
@EricKing: I disagree. It's not that I like JavaScript. I much prefer to use statically typed languages, where static analysis forces you to ensure the operands have sensible types. But if you make it a design philosophy that your language should be forgiving by automatically coercing things at runtime as needed, you can't do it everywhere except with the == operator. The result is would be unusable. Given certain axiomatic design decision, this is sensible behavior. Dismissing that seems like a perfect solution fallacy. –  back2dos yesterday

Yes, I've run across a use case for it, namely when you're comparing a key with a numerical value:

for (var key in obj) {
    var some_number = foo(key, obj[key]);  // or whatever -- this is just an example
    if (key == some_number) {
        blah();
    }
}

I think it's a lot more natural to perform the comparison as key == some_number rather than as Number(key) === some_number or as key === String(some_number).

share|improve this answer

I ran across a pretty useful application today. If you want to compare padded numbers, like 01 to normal integers, == works just fine. For example:

'01' == 1 // true
'02' == 1 // false

It saves you removing the 0 and converting to an integer.

share|improve this answer
2  
I'm pretty sure the 'right' way of doing this is '04'-0 === 4, or possibly parseInt('04', 10) === 4 –  ratbum yesterday
    
I wasn't aware that you could do this. –  Jon Snow yesterday
6  
I get that a lot. –  Jon Snow yesterday
    
@ratbum or +'01' === 1 –  eric_lagergren 16 hours ago

Yes. Virtually every time you want to make a comparison!

This question makes me laugh as the real question should be "Is there ever a GOOD case for using === in javascript?".

I am aware of the differences, however I can categorically say I have never needed ===, ever. It's my impression that people use it quite unnecessarily because they don't want to think about it. But if your comparisions are sane anyway then === is not going to help you!

To me, === often feels 'defensive' and 'cargo cult'. I'd be interested to see your non-contrived example where you positively needed ===.

share|improve this answer
    
downvoter, do comment! –  Tom 11 hours ago
1  
Look at your answer and ask yourself the question: "Am I answering the question that was asked?" –  Robert Harvey 11 hours ago
    
Is that better? –  Tom 11 hours ago
    
This is not an answer to the question. –  Luis Masuelli 43 mins ago

protected by gnat yesterday

Thank you for your interest in this question. Because it has attracted low-quality answers, posting an answer now requires 10 reputation on this site.

Would you like to answer one of these unanswered questions instead?

Not the answer you're looking for? Browse other questions tagged or ask your own question.