Rewriting Prototype to get rid of that ugly side
As part of a recent effort to make the CNET headers a little slimmer and to address some possible conflicts with our code and the javascript that runs from ad developers, I took some time last friday to rewrite Prototype.lite.js - distributed by the mad4milk guys (who make moo.fx).
In my previous post I outlined 3 big problems with Prototype:
- It ain’t tiny
- It’s incredibly addictive, and once you start, you create a dependency on it
- It changes javascript
Now, maybe I can’t fix the second item there - there’s a reason it’s addictive; it makes writing javascript so much more pleasant and, ultimately, more efficient. But I can do something about the other two.
Prototype.lite is a 3KB version of it’s 55K counterpart. It obviously doesn’t have all the same functionality, but it has a few of the most used ones. I won’t go into which ones here, but I find that maybe 90% of the time I don’t need all the other stuff in the full prototype library.
I changed the code in Prototype.lite that extends the array in an effort to fix the last item in that above list: that it changes javascript.
Now, Prototype extends more than just the array class, but the array class it the one that sticks in everyone’s craw, because it adds items to the array that won’t show up if you use the array as an indexed array (i.e. myArray[0] = “something”) but, if you use the array to hold a hash map (i.e. myArray["apple"] = “red”) - which is not what you should do - then when you iterate through those items (for (fruit in myArray) {…}) then you’ll run into the extensions that prototypes add in addition to your content.
So I changed this in Prototype.lite so that it only extends arrays when you tell it to. Prototype has a shortcut to source an object into an array - $A(). So, if you have an object and you do this $A(myObject)[0] it’ll just turn that object into an array (if it can).
I changed the library (Prototype.lite) so that it only extends arrays that are referenced this way. So if you create an array, it’ll behave exactly like it should - no extensions. But if you do this:
var myArray = $A([]);
or
var myArray = $A(["apple", "lemon", "pear"]);
or
var myArray = $A(someFunctionThatReturnsAnArray());
then myArray will have the extentions (most notibly, the .each() extention).
You can also do this:
$A(myArray).each(…);
which gives you the extension without altering the array.
Frankly, I don’t know why this isn’t how it works to begin with. Now we just need to change this in the main prototype library and we’re set. I started doing this on Friday and got about halfway through before I realized that I’m in over my head. I can get most of my changes to pass the unit test, but not all of them. Still, I think it’s possible.
This would let us use the library without colliding with any 3rd party or legacy code. Prototype.lite has the advantage of being very tiny, and I think we can use it most of the time, swapping out the larger library when we need it in a specific context.
Also note that the moo.fx library includes two other code libraries (in addition to the moo.fx animation library) - moo.ajax (2KB) and moo.dom (3KB).
