JavaScript, Technology

Really Understanding JavaScript’s Equality and Identity

=== and !==. First time somebody told me about these two JavaScript operators, I thought she was pulling my legs. I was oblivious to these two operators for the longest time–after all, my JavaScript code had been working just fine with == and !=.

It was not until I found Douglas Crockford’s JSLint that I started wondering about these funny operators. Because JSLint just. Won’t. STOP. COMPLAINING. About almost every single use of == and !=. It gives out error messages like this:

Problem at line 3 character 11: Use '===' to compare with 'null'.

if(id == null) {

Very annoying. But I thought, hey, if Douglas Crockford says so, maybe there’s a good reason behind it, no? So I whipped out my trusty JavaScript: The Definitive Guide to find out more about these operators. (Come on, when was the last time you’re learning a new language and read the operators section?)

Here’s the difference between == and === : == is an operator to check for equality, whereas === is an operator to check for identity. What’s the difference? Well, if you come from a language like Java or C#, you know that just because two objects are equal doesn’t mean they’re identical. That’s what equals() is for–to find out whether two different (that is, nonidentical) objects are equal. Likewise,!= is a inequality operator, and !== is a nonidentity operator.

Fine, that was easy enough. But it ain’t helping. So what? Why is JSLint complaining about x == null? What’s the difference between 3 == 3 and 3 === 3?

The Silent Type Conversion

I dug deeper, and I found something that programmers coming from other languages may find surprising. Examples will illustrate this best (I’m using the jrunscript console that I blogged about here):

js> null == undefined
true
js> null === undefined
false
js> 5 == "5"
true
js> 5 === "5"
false
js> "true" == true
false
js> 1 == true
true
js> "1" == true
true
js> 1 === true
false
js> "0" == false
true
js> "0" === false
false
js> var x = { id: 123, name: "Blah" };
js> var y = { id: 456, name: "Not Blah, definitely" };
js> x == "[object Object]"
true
js> y == "[object Object]"
true
js> x == y
false

So you see that == (and != too) do type conversion under the hood before testing for equality. This may give some very surprising result, such as this:

js> 1 != true
false
js> 0 != false
false
js> 5 != "5"
false
js> var x = new Object();
js> x != "[object Object]"
false

Ahhh so. I finally figured out why JSLint was so fanatical in complaining about == and !=. Because JavaScript does type conversion under the hood when it checks for equality, which may surprise the heck out of programmers from other languages! We can find what the conversions are from ECMA-262 specification… but why? David Flanagan has done it for us in JavaScript: The Definitive Guide. Specifically, the type conversions are:

  1. null and undefined are equal
  2. if a number is compared to a string, the string is converted to a number, and the comparison is done again
  3. true is converted to 1, false to 0
  4. if an object is compared to a number or string, the object is converted to primitive, either by calling its valueOf() or toString() method.

Both === and !== don’t do any of these conversions.

Know What You’re Doing

So what was Douglas Crockford trying to say when his JSLint balked at the use of == and !=? (The latest version seems to be more relaxed in detecting this.)

I believe his point is that we should know what we’re trying to do. Consider the following example:

function doSomething(id, name) {

if(id == null) {

alert("id is mandatory");

}

}

Do you really want to check whether id is null, and do something different if id is undefined? Or you don’t really care whether id is null or undefined, as long as it has some values? If it’s the former, you’ve gotta use ===. For the latter you use ==.

Another example is comparing the contents of an HTML text box with a number. Let’s say you have a textbox containing a person’s age. With ==, it’s convenient:

if(document.getElementById("age").value == 20)

Using === will be troublesome in this situation. So the moral of the story is: really know what you want. The silent type conversion is there to help you, to make things easier for you. But you have to know what’s happening under the hood so you won’t get nasty surprises for cases in which you really mean === (or !==).

About these ads
Standard

12 thoughts on “Really Understanding JavaScript’s Equality and Identity

  1. Pingback: How to write a ruby function that can accept either a string or a regular expression « splintor’s blog

  2. Anonymous says:

    So how does Javascript actually do the test for identity? Is there some kind of hashCode value, or something, that provides the object’s address in memory? Does Javascript use that for code like this:

    myAssociateiveArray[myObject] = ‘hi';

    I.e., does it use myObject’s address for the array index, or does it run some kind of toString() on the object, and use the string as the index? (In which case, how do I code the toString() for my object?)

    • amn says:

      No two objects will ever compare equal, unless the two references actually reference the same object:

      var a = { id: “foo” };
      var b = { id: “foo” };

      a == b; /// false
      a === b; /// false, just FYI

    • amn says:

      There is no implicit toString or valueOf calls being made. If you want to do these sort of things, you will need to explicitly compare the results yourself:

      function Color(value)
      {
      this.value = value;
      }

      Color.prototype.valueOf = function()
      {
      return this.value;
      };

      var a = new Color(0xff0000);
      var b = new Color(0xff0000);

      a == b; /// false
      a === b; /// false

      a == 0xff0000; /// true
      b == 0xff0000; /// true

      a.valueOf() == b.valueOf(); /// true
      a.valueOf() === b.valueOf(); /// true

    • Anonymous says:

      @amn. The question is how it determines identity. Is there some kind of address, or address hash, that the === operator looks at? Thanks. :-)

  3. Great article. You saw the warnings and researched it before changing them, which shows a great deal more foresight than I had when I saw the warnings, changed them, checked in the code, and broke our product in crazy mysterious ways.

    Go me.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s