Does using == in JavaScript ever make sense?

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

' trn ' == 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?

16

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

' trn ' == 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.

22

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.

9

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 😉

11

As a professional mathematician I see in Javscript’s sameness operator == (also called “abstract comparison”, “loose equality”) an attempt to build an equivalence relation between entities, which includes being reflexive, symmetric and transitive. Unfortunately, two of these three fundamental properties fail:

== is not reflexive:

A == A may be false, e.g.

NaN == NaN // false

== is not transitive:

A == B and B == C together do not imply A == C, e.g.

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

Only symmetric property survives:

A == B implies B == A, which violation is probably unthinkable in any case and would lead to serious rebellion 😉

Why equivalence relations matter?

Because that is the most important and prevalent type of relation, supported by numerous examples and applications. The most important application is decomposition of entities into equivalence classes,
which is itself a very convenient and intuitive way of understanding relations. And failure to be equivalence leads to the lack of equivalence classes, which in turn leads to the lack of intuitiveness and unnecessary complexity that is well-known.

Why is it such a terrible idea to write == for a non-equivalence relation?

Because it breaks our familiarity and intuition, as literally any interesting relation of similarity, equality, congruence, isomorphism, identity etc is an equivalence.

Type conversion

Instead of relying on an intuitive equivalence, JavaScript introduce type conversion:

The equality operator converts the operands if they are not of the same type, then applies strict comparison.

But how is the type conversion defined? Via a set of complicated rules with numerous exceptions?

Attempt to build equivalence relation

Booleans. Clearly true and false are not same and should be in different classes.

Numbers. Luckily, the equality of numbers is already well-defined, in which two different numbers are never in the same equivalence class. In mathematics, that is. In JavaScript the notion of number is somewhat deformed via presence of the more exotic -0, Infinity and -Infinity. Our mathematical intuition dictates that 0 and -0 should be in the same class (in fact -0 === 0 is true), whereas each of infinities is a separate class.

Numbers and Booleans. Given the number classes, where do we put booleans? false becomes similar to 0, whereas true becomes similar to 1 but no other number:

true == 1 // true
true == 2 // false

Is there any logic here to put true together with 1? Admittedly 1 is distinguished, but so is -1. I personally don’t see any reason to convert true to 1.

And it gets even worse:

true + 2 // 3
true - 1 // 0

So true is indeed converted into 1 among all numbers!
Is it logical? Is it intuitive? The answer is left as exercise 😉

But what about this:

1 && true // true
2 && true // true

The only boolean x with x && true being true is x = true. Which proves that both 1 and 2 (and any other number than 0) convert to true! What it shows is that our conversion fails another important property — being bijection. Meaning that two different entities can convert to the same one. Which, by itself, does not have to be a big problem. The big problem arises when we use this conversion to describe a relation of “sameness” or “loose equality” of whatever we want to call it. But one thing is clear — it is not going to be an equivalence relation and it is not going to be intuitively described via equivalence classes.

But can we do better?

At least mathematically — definitely yes!
A simple equivalence relation among booleans and numbers could be constructed with only false and 0 being in the same class. So false == 0 would be the only non-trivial loose equality.

What about strings?

We can trim strings from whitespaces at the beginning and the end to convert to numbers, also we can ignore zeroes in front:

'   000 ' == 0 // true
'   0010 ' == 10 // true

So we get a simple rule for a string — trim the whitespaces and zeroes in front. Either we get a number or empty string, in which case we convert to that number or zero. Or we don’t get a number, in which case we don’t convert and so get no new relation.

This way we could actually get a perfect equivalence relation on the total set of booleans, numbers and strings! Except that … JavaScript designers obviously have another opinion:

' ' == '' // false

So the two strings that both convert to 0 are suddenly non-similar! Why or why? According to the rule, strings are loosely equal precisely when they are strictly equal! Not only this rule breaks the transitivity as we see, but also it is redundant! What is the point of creating another operator == to make it strictly identical with the other one ===?

Conclusion

The loose equality operator == could have been very useful if it were abiding to some fundamental mathematical laws. But as it sadly doesn’t, its usefulness suffers.

2

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).

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.

6

I know this is a late answer, but there seems to be some possible confusion about null and undefined, which IMHO is what makes == evil, more so that the lack of transitivity, which is bad enough. Consider:

p1.supervisor = 'Alice';
p2.supervisor = 'None';
p3.supervisor = null;
p4.supervisor = undefined;

What do these mean?

  • p1 has a supervisor whose name is “Alice.”
  • p2 has a supervisor whose name is “None.”
  • p3 explicitly, unequivocally, does not have a supervisor.
  • p4 may or may have a supervisor. We don’t know, we don’t care, we’re not supposed to know (privacy issue?), as in it’s none of our business.

When you use == you are conflating null and undefined which is wholly improper. The two terms mean completely different things! Saying that I don’t have a supervisor simply because I refused to tell you who my supervisor is is wrong!

I understand there are programmers who don’t care about this difference between null and undefined or choose to use these terms differently. And if your world does not use null and undefined correctly, or you wish to give your own interpretation to these terms, so be it. I don’t think that’s a good idea though.

Now by the way I have no problem with null and undefined both being falsy! It is perfectly okay to say

if (p.supervisor) { ... }

and then null and undefined would cause the code that processes the supervisor to be skipped. That is correct, because we don’t know or don’t have a supervisor. All good. But the two situations are not equal. This is why == is wrong. Again, things can be falsy and used in a duck typing sense, which is great for dynamic languages. It is proper JavaScript, Pythonic, Rubyish, etc. But again, these things are NOT equal.

And don’t get me started on non-transitivity: "0x16" == 10, 10 == "10" but not "10" == "0x16". Yes, JavaScript is weakly types. Yes, it is coercive. But coerciveness should never, ever, apply to equality.

By the way, Crockford does have strong opinions. But you know what? He is correct here!

FWIW I understand that there are, and I have personally run into, situations where == is convenient! Like taking string input for numbers and, say, comparing to 0. However, this is hack. You have convenience as a tradeoff for an inaccurate model of the world.

TL;DR: falsiness is a great concept. It should not extend to equality.

1

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật