Javascript heresy 5
So, remind me, what’s the rationale for always using the optional ; when you’re writing Javascript? The only reasons I can think of, off the top of my head are, “Because you’ll break minifiers without it” and “Because Douglas Crockford doesn’t like it”. Well, broken minifiers that can’t parse the language correctly can kiss my fat hairy arse and argument from authority cuts little ice here.
Gareth Rushgrove pointed me at an article, which suggested that it’s because Javascript will insert a semicolon after the return in:
return
{ key: "value" }
But that’s not exactly surprising, and falls squarely into the “Don’t do that then” category of bugs, or putting it another way, the Dominus Doctrine (“You can’t just make shit up and expect the computer to know what you mean, retardo!”) applies.
Ruby also has an optional semicolon, but good style is avoid using them and we seem to survive. In fact, the Ruby parser is rather less capable than Javascript’s:
jQuery('.class')
.addClass('whatever')
.html('New inner HTML')
is legal Javascript, but, in Ruby you have to write:
jQuery('.class') \
.addClass('whatever') \
.html('New inner HTML')
because if you don’t the compiler throws its toys out of the pram and, for bonus points, the resulting parse error implies that the parser knows what you meant but decided to throw the error anyway. Ho hum.
Is there something I’ve missed? Or should I make a preemptive stand against incompetent minifiers and start writing my Javascript without semicolons?
Updates
In the comments, “James” offers a succinct piece of code using Prototype that demonstrates the problem rather neatly. In the absence of semicolons, code like:
var foo = 3
, bar = 2 + foo
[foo, bar].each(function (i) { console.log(i) })
gets parsed as
var foo = 3
, bar = 2 + foo[foo, bar].each(...)
Which isn’t exactly what you want. If I were feeling churlish, I might argue that such problems are one reason why the jQueryish way:
var foo = 3
, bar = 2 + foo
$.each([foo, bar], function () {...})
is a better way of iterating over things, but I’m not entirely sure that it is.
Looks like I’ll keep taking the semicolons.
Work with us 2
If the last post about our Javascript issues didn’t put you off, then you might be interested to know that we’re hiring. If you’re an experienced, test infected Ruby on Rails programmer with some Javascript and a real world consumer website or two under your belt, and you’re happy to work in Newcastle upon Tyne, then we definitely want to hear from you. I’d probably be interested in at least hearing from you if you’re an experienced dynamic language programmer who has only recently made (or is considering making) the switch to Ruby and Rails. It’s only syntax after all.
The money’s decent, the work is interesting, the people (well, apart from me, obviously) are great, and Newcastle’s a fantastic city. Drop me a line, ping me on AIM/gTalk/Twitter or just send your CV to the jobs@amazing-media.com.
Usability testing (throws) rocks 4
Usability testing is wonderful. But wow, its humiliating.
I’ve spent the last few weeks working on the Amazingtunes in page player. Amazingtunes is a music site, so we need to play music. However, we don’t like the way that most music sites work; either the music stops as you go from one page to another, or the player is a huge Flash app running in its own window. There has to be a better way. There needs to be a popup window if you want to eliminate stop/start behaviour, but there’s surely no reason not to keep the controls on the main page.
So, we set about writing somthing that did just that. We settled on using Jeroen Wijering’s excellent flvPlayer, which handles the media formats we need and has good Javascript control and communications. This sits in the child window and we use Javascript cross-window communication to have a player controller in the main window that looks something like:
This is all done in HTML and and Javascript, the progress bar does the Safari trick of running behind the tune data links, the buttons do their AJAX magic and the whole thing is rather slick, though I say so myself.
At least, we thought it was slick until we pointed the usertesting.com legions at it. Without exception, they ignore the in page player, foreground the popup and use the teeny weeny controls on the flash player. Originally, the popup window didn’t even display any transport controls, it just had a picture of some speakers and some text asking the user not to close it because it was playing the tunes. We added transport controls as a stopgap while we made the in page player work properly.
I sound like I’m whinging don’t I? It’s certainly a blow to the ego to see something we spent so much time and attention on being ignored by our sample users. On at least one occasion, while watching the screencasts I found myself boggling at the things the users did, and if I didn’t shout “Just play some bloody music!” at the screen, then I came worryingly close.
It would be easy to retreat into a state of denial: “They’re not our target users! They’re stupid! They’re American! If they would only magically intuit the way we think they should use the site!”. And maybe it would be comforting to do so, for a while. The right thing to do is to suck it up – take away from those videos the sure and certain knowledge that bits of the site don’t work and do something about it.
We may dislike the ‘popup window for transport controls’ model of controlling music playback, but users are cool with it. And it’s not as if the work we did on making the in page player work is going to be wasted – widget is straightforwardly event driven so it’ll work just as well in the popup window, and the communication protocol will be much simpler. Having the player in its own window means we’ll be able to extend its interface in ways that would be hard when the player had to share window space with the rest of the page. In the end, it’s all good.
But… damn that in page player was sweet. I learned Javascript as I wrote it (mostly by pretending it was Perl with odd syntas) and I’m bloody proud of it. I’ll happily replace it with the next iteration (which I’m already working on), but it’ll be with a pang of remorse all the same.
A quick Javascript formatting tip 10
IE’s a pain. The particular pain I want to write about is its pickiness about Javascript object literals. Consider the following Javascript object:
{ success: function () {...},
failure: function () {...},
}If you’re used to programming in Perl or Ruby, that trailing comma’s perfectly fine, in fact leaving it there is sometimes considered good practice because it makes it easy to extend the hash, just add a new row and leave another trailing comma.
The trouble is, it’s not strictly legal to do that in Javascript. Pretty much every implementation out there will allow it though.
Except IE.
So, I’ve taken a leaf out of Damian Conways Perl Best Practices and writing my object literals as:
{ success: function () {...}
, failure: function () {...}
}By sticking the comma at the beginning of the line, I’m never going to make an object that breaks IE, and adding a new line to the hash is straightforward too. Just stick the cursor in front of the }, type my leading comma, space, attribute name, and hit return when I’m finished.
I’ve also started using the same practice pretty much everywhere else that I’ve got a comma separated list of things:
var foo
, bar
, baz
;
$.each( anArray
, function () { ... }
);It looks weird at first, but trust me, it grows on you.
Update
In the comments, I make reference to tweaking Steve Yegge’s excellent js2-mode to handle leading comma style a little more gracefully. Since then, I’ve made it work and attached a diff to this issue on the project’s issue tracker.
Javascript scoping makes my head hurt 13
Who came up with the javascript scoping rules? What were they smoking. Here’s some Noddy Perl that demonstrates what I’m on about:
my @subs;
for my $i (0..4) {
push @subs, sub { $i }
}
print $subs[0]->(); # => 0;Here’s the equivalent (or what I thought should be the equivalent) in Javscript:
var subs = [];
for (var i in [0,1,2,3,4]) {
subs[i] = function () {
return i;
}
}
alert subs[0]() // => 4What’s going on? In Perl, $i is scoped to the for block. Essentially, each time through the loop, a new variable is created, so the generated closures all refer to different $is. In Javascript, i is scoped to the for loop’s containing function. Each of the generated closures refer to the same i. Which means that, to get the same effect as the perl code, you must write:
var subs = [];
for (var shared_i in [0,1,2,3,4]) {
(function (i) {
subs[i] = function () {
return i;
};
})(shared_i);
}
subs[0]() // => 0Dodgy Ruby scoping
I had initially planned to write the example “How it should work” code in Ruby, but it turns out that Ruby’s for has the same problem:
subs = [];
for i in 0..4
subs << lambda { i }
end
subs[0].call # => 4Which is one reason why sensible Ruby programmers don’t use for. If I were writing the snippet in ‘real’ Ruby, I’d write:
subs = (0..4).collect { |i|
lambda { i }
}
subs[0].call # => 0My conclusion
Javascript is weird. Okay, so you already know this. In so many ways it’s a lovely language, but it does have some annoyingly odd corners.
Getting to grips with Javascript
I’ve been busily adding AJAX features to the work website, and I got bored of writing Form handlers. I got especially bored of attaching similar form handlers to lots of different forms on a page, so I came up with something I could attach to document.body and then plug in handlers for different form types as I wrote them.
So, I wrote FormSender and set up my event handler like so:
FormSender.onSubmit = function (e) {
if (canDispatch(e)) {
YAHOO.util.Event.stopEvent(e);
YAHOO.util.Connect.setForm(e.target);
YAHOO.util.initHeader('Accept', 'application/javascript, application/xml');
YAHOO.util.Connect(e.target.method.toUpperCase(), e.target.action,
callbackFor(e));
}
};
jQuery(document.body).each(function () {
YAHOO.util.Event.addListener(this, "submit", FormSender.onSubmit);
});I decided to mark any Ajax dispatchable forms using a class of ‘ajax’, the idea being that it would be a simple thing to check
jQuery(e.target).hasClass('ajax'), but there was a snag. We had two sorts of forms on our pages, forms built using form_for(..., :class => 'ajax') and forms built using button_to(..., :class => 'ajax'), and they attached their classes in different places. In the form_for case, the class was on the form tag, but in the button_to case, it was on the generated form’s submit field. One option would be to monkey patch button_to, or roll my own ajax_button_to, but I ended up writing canDispatch like so:
function canDispatch(e) {
jQuery(e.target).find(':submit').andSelf().hasClass('ajax');
}This uses jQuery to build a list of the form, and its submit button, and then checks to see if any member of that list has the class ‘ajax’.
So, we can now tell if the source of a submit event is a form we should be doing AJAX dispatch with. The next trick is to work out what needs to be done with the results of sending the form. One option is the Prototype trick of simply evaluating the returned javascript, but it often makes sense to keep the behaviour clientside and just have the server return a datastructure. I decided that the way to do this would be by adding a second class to a form which used a none default handler, and then keep a hash of callback constructors keyed by class. This made callbackFor look like:
function callbackFor(e) {
var candidates = candidateClasses(e.target);
for (var i = 0; i < candidates.length; i++) {
if (FormSender.callbacks[candidates[i]]) {
return new FormSender.callbacks[candidates[i]](e);
}
}
return new FormSender.callbacks.ajax(e);
}candidateClasses is, again, a little more complex than I’d like, by virtue of the differences between button_to and form_for differences, but still reasonably straightforward, thanks to jQuery:
function candidateClasses(element) {
return
jQuery(element).find(':submit').andSelf()
.filter('.ajax').attr('className')
.replace(/ajax/, '').trim().split(/ +/);
}JQuery gets the form and its submit button, then selects the tag that has the ‘ajax’ class and pulls out the full className string. The replace gets rid of ‘ajax’, trim chops any useless whitespace off either end, and split(/ +/) turns it into an array of classnames. The replace -> trim -> split pipeline has the feel of something that must already exist in some DOM interface somewhere, but I’m not sure where, so I rolled my own.
Once we have a list of classes it’s easy to just cycle through the candidates until we find one that matches a callback constructor, falling back to the default where nothing matches.
For completeness, I’ll show you my current default handler, which I expect to be extending to deal with a couple more media types and, in the case of the failure handler, more failure statuses.
FormSender.callbacks.ajax = function (e) {
var form = e.target;
this.scope = form;
};
FormSender.callbacks.ajax.prototype.success = function (o) {
switch (o.getResponseHeader['Content-Type'].replace(/;.*/, '')) {
case 'application/javascript':
case 'application/x-javascript':
case 'text/javascript':
eval(o.responseText);
break;
default:
YAHOO.log("Can't handle AJAX response of type " + o.getResponseHeader['Content-Type']);
}
};
FormSender.callbacks.ajax.prototype.failure = function (o) {
switch (o.status) {
case 401:
Authenticator.loginThenSubmit(this);
break;
default:
switch (o.getResponseHeader['Content-Type'].replace(/;.*/, '')) {
case 'application/javascript':
case 'application/x-javascript':
case 'text/javascript':
eval(o.responseText);
break;
default:
YAHOO.log("Can't handle AJAX failure response of type " + o.getResponseHeader['Content-Type']);
}
}
};You’ll notice a reference to Authenticator.loginThenSubmit in the 401 handler, but that’s something I’ll save for another day.
A note on namespacing
Although I’ve been showing the various FormSender helper functions as if they were in the global namespace, in the real code they’re wrapped in a function call:
var FormSender = (function () {
var candidateClasses = function (element) {...};
var callbackFor = function (e) {...};
...
var onSubmit = function (e) {...};
return {onSubmit: onSubmit, callbacks: {}};
})();I love the (function () {...})() pattern – it’s a great way of keeping your paws out of the global namespace until you really, really need to.
FormSender Benefits
Aside from the obvious benefit of drastically reducing the number of onSubmit event handlers registered with the browser, I found that using FormSender has simplified some of my response handlers. For instance, one form would get a chunk of html back from the server and would use that to replace the div that contained the form. But the new div also contained a form that needed to have Ajax behaviour, so a chunk of the handler code was concerned with reregistering onSubmit handlers for the new form (or forms). No fun. By switching to a single, body level, form handler, that problem simply disappears – so long as the new forms have the right class, they automatically get the appropriate behaviour. Result.
Obviously, FormSender is unobtrusive javascript, which is nice, and its pluggable nature means it’s easy to extend just by writing new response handlers and registering them with the FormSender object.
Future Directions
One obvious extension to FormSender is to pull out the meat of the onSubmit method into the callback object to allow for forms that don’t simply send themselves to the server. Another is to wrap my head around the workings of Javascript’s object model to make it easy to build handlers that don’t duplicate the behaviour of the default handler through the medium of copy and pasting code…
Your comments please?
I’m still very new to Javascript as a programming language and I’m sure I’m doing plenty of boneheaded things here. Please let me know if there’s things I can do to improve this, or point me at any libraries that already cover this ground.
So... I was wondering 3
Has anyone written an Atompub client in JavaScript yet?
Finally learning JavaScript 10
For years I’ve managed to dodge learning JavaScript. People have told me it’s a fine language with some dodge implementations. Friends have built an entire business model in the language, and I’ve continued to treat as if it were The Sound of Music (I’m 39 now and I have managed to completely avoid watching that film).
Except, today I finally had a technical need that I couldn’t dodge by writing another .rjs file, so with the help of the Prototype docs, a helpful article or two and healthy dose of cribbing from others, I was off.
What do you know, it really is a fine language. I doubt I’m writing idiomatic code though – I’m leaning heavily on closures and private member functions, and I haven’t written a single for loop yet, but it seems to accommodate my style.
Now, if I can just get my head round the innards of keyboard events I shall be a great deal happier.

