Javascript Object Promotion
So it’s not something you should have to worry about (often), but I just spent an inordinate amount of time figuring out exactly why a particularly innocuous-looking piece of code was failing. It’s also yet another surprising part of the javascript language, and if you often deal with javascript then it’s in your best interests to keep track of such oddities (there are a lot of them!).
To illustrate, consider the following array intersection function:
You might expect calling intersect(list1, list2)
to return ["a", "b"]
, since those are the common elements in the two sets. However, what you really get is []
.
The problem is that I was a bit lazy, and used jQuery.each()
to iterate over my collection (I hate the for x in y
construct, and for
loops are just so C
). The each
method calls your provided function on each member of the provided array, setting this
in the context of each call to the current array element.
But it turns out that when you call a method on a primitive string
object, the javascript (well, ECMAScript really) language specifies that this call takes place not on the string
primitive type, but on the String
object type (it’s kinda like a boxed value in Java). That is, fun.call("some string")
actually ends up as if you had written fun.call(new String("some string"))
.
The String
and string
objects will compare equal when using the “==” operator - but since they are of different types, they will not compare as equal using the “===” operator. Evidently that is the type of equality that indexOf()
uses, therefore none of the String
objects will ever appear in the array of string
primitives.
Normally, you will neither notice nor care. However, when extending the String class or calling a function with a primitive type as the subject, you should keep this conversion in mind. Note that the conversion does not apply to function arguments, only to the subject of a function application (i.e this
).
I’m continually amazed by the high quality answers found on stackoverflow.com - I posted this question asking why the object promotion occurs (and if that is indeed what’s going on), and was rewarded with an explanation and a link to the precise part in the ECMAScript spec where the behaviour is detailed.