In the coming months, all of the major browser vendors are going to implement a new API called
querySelectorAll, which allows us web developers to query a document for elements matching a CSS3 selector and quickly get back a list of matching nodes. This is really fantastic news and should help to speed up one of the more common things we do in web apps.
We have basic support for the API in the latest Firefox 3.1 nightlies, IE8 beta 2, and WebKit, and Dojo has basic support in trunk for using
querySelectorAll to drive
dojo.query if itís available, so I thought Iíd try it out and see what happens.
Well, things Ö mostly Ö work. The selection stuff is great, but Dojo does one rather nice thing with the
dojo.query interface: it returns an
Array object thatís been decorated with the JS 1.7 array methods if theyíre not natively available, plus some other Dojo-specific things, like
style and so forth, to make running operations against the result set easy. For some reason, a number of these methods were broken.
I did some digging and it turns out that the breakage is happening because the
querySelectorAll return is not an
Array or a subclass of an
Array, but a new thing called a
StaticNodeList. It looks mostly like an array and works like an array, but it doesnít have any of the new array methods (at least on Firefox 3.1 and IE8 beta 2) and as itís not an array, it fails an
instanceof check. This means code like this:
var spans = document.querySelectorAll("span"); var divs = document.querySelectorAll("div"); var both = spans.concat(divs); // fails, no concat method
just plain doesn’t work. JS devs already have this array-ish problem with the return from
document.getElementsByTagName and the
arguments object available inside functions. From looking at the spec for the
StaticNodeList, I cannot for the life of me see why this isn’t just a plain array with the standard array methods on it. It’s a static collection, so treating it just like an array should be fine, no?
If anyone can shed light on why the returned value from querySelectorAll is not just a plain JS array, Iíd love to hear it.
1 reply on “Yay for querySelectorAll. Boo for StaticNodeList.”
Even stranger is it seems that it was decided that Array was a better idea:
Don’t ask me what happened there. I find this frustrating.
Is there an easy way to convert a StaticNodeList to an Array? The only workaround I’ve found so far is using the generic Array functions, so instead of:
a.map(…) // a is a StaticNodeList
you just do:
…and it works.