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? Well, here's a problem:
if (null != this.datapath && dp != LzNode._ignoreAttribute) {
this.datapath.setXPath(dp);
} 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.
[...]
20. 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.]