Space Vatican

Ramblings of a curious coder

Javascript: Not as Shit as You Thought

For a long time javascript was something I avoided like the plague, usually only ever handling with the rubber gloves that rails provides. On a few occasions I had written some raw javascript myself and quite frankly I felt dirty afterwards and started hitting the bottle rather hard. I was writing clumsy procedural code, verbose, without unit test and working round all sorts of quirks in the language. Sometimes it was the only choice but whenever I could avoid it, I did.

This year I’ve been doing quite a lot of work in javascript, as part of a supercool project at work. However I am not an alcoholic nor a gibbering wreck. So what happened? In a single word, prototype (note that a lot of what I’m saying probably applies to similar libraries like jQuery, dojo etc… The important stuff isn’t really in the details).

Getting Prototypical

Now I’d heard of prototype before. It was that thing with the $ thing for getting dom elements by id that you had to include for the whizz-bang scriptaculous magic or for using ajax. Thanks to my blind raging hatred of javascript I’d never looked any closer. What a mistake! There is so much more to prototype, something which I discovered thanks to the Bungee Book which is a lovely piece of work (Seriously, stop reading this and go and buy it. It’s great (apart from the index)).

Fun in the Browser

Prototype brings two unrelated (at least at the conceptual level) things together. The first is a whole pile of things that make make the browser environment more palatable. The $ function is but the tip of the iceberg here. Some of my favourites include

  • $$ (and Selector class that powers it): find all the elements in the document matching a CSS rule. The great thing here is that it knows a whole pile of tricks, even if you’re browser doesn’t, so you can go from the basic $$(‘p.alert’) (all paragraphs with class alert) to things that are a little more fun:
x.js
1
$$('.sources .source:not(.disabled)')

( all elements inside something with class ‘sources’ that have the class ‘source’ but not the class disabled).

  • down, next, up etc… Navigating the dom by hand is the biggest pain in the arse since Vlad the Impaler, but these functions make it oh so easy. The up function gives you the parent element, down gives you the first descendant and so on (and of course you can say ‘give me the 3rd such element’). That in itself is a modest improvement in comfort. But the killer blow is that you can pass those lovely css selectors and say things like
x.js
1
foo.down('.source:not(.disabled)')

which does exactly what it should: keep going down until you find something that matches that selector. Now think about how you’d do that by hand!

  • Event handling: prototype smoothes over all the differences between browsers and makes it really easy to have your own custom events which is great for having page elements react to changes without coupling things too tightly

  • Style manipulation: getStyle (gets computed styles), setStyle, hasClassName, removeClassName, addClassName are just terrific. Before

x.js
1
2
3
foo.style.left = '8px';
foo.style.right = '8px';
foo.style.top = '8px';

After

x.js
1
foo.setStyle({left: '8px', right: '8px', top: '8px'})

There’s loads more of this sort of stuff, the list above is just what sprung to mind. All the way prototype hides the differences between browsers.

Inner Beauty

Great stuff, but it doesn’t address the issues of Javascript’s builtin classes and the language itself. In a way I think this is where prototype really shines, because after a while I couldn’t feel that feeling of self-loathing anymore. I was actually enjoying writing javascript. Part of it is down to the fact that beneath the horribleness of the 90s there’s actually some cool stuff in javascript: closures, functions are objects and so on. The trouble is I’d never noticed because I was so busy vomiting profusely at the rest of it. Prototype made me aware of the nice stuff and tidies up the dog turds (And if you ignore everything I’ve written but remember that javascript has these functional hiding inside then that’s probably the most important thing).

Enough waffling. What does prototype give you in this deparment? – Enumerable. A beast of a module. Mixed in to Array by default, it lets you use each, inject, map almost as if you were writing ruby (there’s some punctuation clumsiness, but that’s not prototype’s fault). If that sounds awfully similar to ruby’s Enumerable that’s because it is – Class. Write classes, subclass them = win – method binding – Loads of little utilities like Object.isFunction that really should have been there all along – Your sanity back.

It’s really a joy the first time you write javascript using all this. Seriously it brought tears to my eyes.

Feeling Testy?

The one bit missing from my workflow was unit testing. I started of playing with jsunit and while it worked fine I wasn’t really enjoying it. There just seemed to be too much machinery involved, and some things seemed needlessly complicated. For example if you want to run a test suite in the browser you have to open the testRunner page, then click on the choosefile button on that page, navigate to your test file and hit run. And because of that you can’t just set a firebug breakpoint. I ended up loading the test file itself in the browser and calling the setup, test and teardown functions from the firebug console. Yuck.

I know a lot of this is built for flexibility, but it was just completely overkill for what I needed. It turns out that prototype itself has a handy little unit testing framework that was much closer to what I was looking for. There’s even the javascript_test plugin which makes all that fit nicely into your rails app (although it would seem that javascript_test hasn’t seen much love – I’ve ended up ripping out most of its innards and replacing them with the lastest stuff from prototype). If you want to run a test suite in your browser, just open the test file! A rake task lets you run them all in one go

Started tests in Firefox
.......................
Finished in 23 seconds.
116 tests, 545 assertions, 0 failures, 0 errors

Finally, peace. Maintainable, structured, nonverbose javascript code, unit tested and running off a CI server. Who would have expected that!