spacer spacer spacer


Equality and Identity in Javascript

A reader from Plymouth writes,

So I’m profiling along, and I find an anonymous function that is being called a number of times. It doesn’t cost a lot, but I’m curious why it is anonymous. It’s not really anonymous, because our compiler assigns a debugging name to anonymous functions that you can use to find them in the source. Here’s the anonymous function:

static var _ignoreAttribute = {toString: function () {
      return '_ignoreAttribute'}};

_ignoreAttribute is just a unique sentinel object that we use as a way to indicate that an attribute has already been processed, deep in the inner workings of LZX. Someone (probably me) graciously gave it a toString method, so that when you are debugging and trip across it, you will realize that it is not just any old empty object.

But I’m not debugging. I’m profiling. I’m not calling _ignoreAttribute.toString(). It’s nowhere in the source code that I can see. What is going on?

Gentle reader,

Well, here’s a problem:

if (null != this.datapath && dp != LzNode._ignoreAttribute) {
} else {

Can you spot it? When dp != LzNode._ignoreAttribute runs, dp is normally a string, and read the fine print for how equality is computed in Javascript (from p. 64 of ECMAScript Language Specification Edition 3):

  1. If Type(x) is different from Type(y), go to step 14. […]
  2. If Type(x) is either String or Number and Type(y) is Object, return the result of the comparison x == ToPrimitive(y).

Well, I won’t bore you with more gory details, but the bottom line is, every time we compare _ignoreAttribute to a String, the runtime has to call its toString method to see if it is “equal”.

The storal of the morey is, when you want to compare for “identity”, use the “strict equals operator” (=== or !==), not the “equals operator”. [For my money, the former should have just been called the “identity” operator, but unfortunately it isn’t quite. There are some odd edge cases that make it not a true identity operator.]

19:10 | Link | Reply | Track