When I started working on the animation framework
glitz.js, I wanted an easy syntax for expressing and traversing a nested tree of
Renderable objects. I thought, ”Why not implement it as an array?” Since the scene graph would need to be iterated over very quickly during the render loop, it would be great to just represent the whole thing as a multi-dimentional array – essentially a subclass of array that had some additional properties and methods like
1 2 3 4 5
First I tried a simple approach.
1 2 3 4 5 6 7
Basically, you can invoke methods from the native
1 2 3 4
At first glance (eg, not in
IE<8), this seems to work great. However, there are hidden dragons – let’s compare some further manipulations to a native array.
1 2 3 4 5 6 7 8 9 10 11 12
Uh-oh, there are obviously some drawbacks here. First, setting the length property of a proper
0 clears the array. In fact, this is usually the fastest method of clearing arrays. Second, when you assign a value to an array index that is
> length, then the native array will expand to contain it. In short, native arrays have a magical
length that we miss out on entirely with the naive approach. As usual, more information can be found in the relevant section of the EMCAscript spec.
Okay, so my naive approach is dead in the water – after grieving, I decided to try direct extension. This is exactly what it sounds like: creating
Array instances and copying a bunch of methods & properties on to them directly.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
The outcome here is exactly what we want – a native array with some extra methods and properties. There’s just one problem, compared to creating raw instances of a native array, it is really, really slow – for example, in Firefox 17.0, it is 26 x slower when adding just two properties.
Now obviously there are a lot of use cases where this performance hit isn’t particularly painful – even at 1/26th speed you can still create many thousands of arrays per second, and probably most uses for
glitz.js wouldn’t suffer too badly here. But, this is in an animation framework and if we can speed any part of it up by that much, it increases the domain it can operate in by a fair margin. This brings us to…
Wouldn’t it be the best if we could just subclass
Array and add some methods to the
Renderable subclass requires a different set of extentions to the
prototype and trying to use prototypical inheritance runs into the same issues as the naive solution.
Enter Dean Edwards iframe sandbox solution – the idea here is that you create a hidden
<iframe> and steal the
Array object from the
iframe execution context.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
- Keep that iframe around and attached to the DOM – it still technically owns our array.
- This approach doesn’t work in non-browser environments.
Number 2 is not a problem this purpose as
glitz.js is already tied to the browser in other ways. Additionally, if it were ever to be ported to a server context this same methodology could be recreated with a slightly different technique, such as borrowing
Array from a
Ultimately this is the technique I used for a major update to the way that
glitz.js handles array subclassing under the hood in commit
5c5d183 and also ended up putting together
gimme a tiny stand alone library to automate the process of “borrowing” natives.