Issues with Crockford’s JavaScript conventions

I’ve been reading up on Douglas Crockford’s Code Conventions for the JavaScript Programming Language and I agree with most of them, but I definitely have a bone to pick with one of them: “All variables/functions should be declared before they are used.”

This sounds good in theory, and is probably a good programming practice. However, in JavaScript we frequently use callbacks to implement asynchronous calls, due to the fact that JavaScript is single-threaded. Code like this is common:

function BeginProcess(data) {
    // process data
    DoDataProcess({
        'data': data,
        'onComplete': EndProcess
    });
}

function EndProcess() {
    alert('The process is done');
}

Think AJAX in particular. This kind of thing is commonplace. However, declaring things before we use them means we have two options. We can either swap the functions around, or we can declare var EndProcess; at the top of the script. The latter reminds me too much of C, where you have to declare function prototypes ahead of time if you want to write them in any order you want. The former is just incredibly confusing. Consider how that would look:

function EndProcess() {
    alert('The process is done');
}

function BeginProcess(data) {
    // process data
    DoDataProcess({
        'data': data,
        'onComplete': EndProcess
    });
}

This is horrible. The natural code flow is broken. You now have to start at the last function and read it, then go up to read the next part. This is the same reason that top-posting sucks and bottom-posting makes sense. If those functions were both longer than a screen, you have to scroll to the bottom of the script, then up to the function header. Then read down to find “EndProcess” and say “what’s that?” Then scroll up to find EndHeader, then back down to read it. The human mind has not been conditioned to read this way.

Consider this quote from the linked article on top-posting:

Top-posting makes posts incomprehensible. Firstly: In normal conversations, one does not answer to something that has not yet been said. So it is unclear to reply to the top, whilst the original message is at the bottom. Secondly: In western society a book is normally read from top to bottom. Top-posting forces one to stray from this convention: Reading some at the top, skipping to the bottom to read the question, and going back to the top to continue. This annoyance increases even more than linear with the number of top-posts in the message. If someone replies to a thread and you forgot what the thread was all about, or that thread was incomplete for some reasons, it will be quite tiresome to rapidly understand what the thread was all about, due to bad posting and irrelevant text which has not been removed.

Given a suitably large enough application (like the one I am working on right now) this means that I either need about 200 var statements at the top of my program to indicate every class I am defining, and the same within each class to indicate each private function, or I have to reorder them. Both are unwieldy. One is unnecessarily verbose, while the other is horrible to read and breaks the natural flow of the code. Your initialization function winds up at the very bottom of the script, then you have to work your way up to see what is going on.

Crockford seems like a pretty intelligent guy, but I’ve yet to see any extensive code samples that show how he gets around this problem. Thoughts?

6 Replies to “Issues with Crockford’s JavaScript conventions”

  1. With mutual recursion, there’s no choice but to live with an undeclared symbol, unless one is to use explicit closures held in declared variables.

    However, for your callback example, I personally prefer the style where the callback is declared before it is used. Perhaps it is a preference that has stayed in my mind since I used to program in Pascal, or its related to my knowledge of how compilers work, but I do like to see symbols defined before they are used as I read forward through the code.

  2. Declaring variables is aimed at preventing global namespace polution. If you’re not polluting the global namespace with your functions, then you need not worry.

  3. @Barry:

    At least in JavaScript all functions are closures anyway. Since “function foo() { … }” means the same thing as “var foo = function () { … };” there will be no overhead if you predeclare a variable. Still ugly though.

    I guess we just have a stylistic difference when it comes to how we read code.

  4. Crying out for a Haskell where clause… it’s just syntax but it lets you put local declarations at the end of code rather than before.

    function foo = blah doStuffLater where
    doStuffLater = ….

  5. I realize this is an old post, but the title caught my eye. When you use a function declaration, it is ‘hoisted’ to the top of the current scope by the interpreter for you. Crockford’s convention is to predefine function expressions.

    Here is a good article I just found that demonstrates this behavior: http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting. I actually found it out watching Crockford’s video series on javascript, http://developer.yahoo.com/yui/theater/video.php?v=crockonjs-3.

  6. It’s a matter of preference. When reading code I prefer to read the functions that I’m going to come across before they are used. That way when you read the main code body you aren’t confused about what all of these undeclared variables are. You’ve seen them already at the top of scope and you know that they do what you expect them to do based on context and their name (hopefully).

    So it reads like “here are the tools we are going to be using below, ok now lets use them.” Rather than, “let’s do all this stuff, trust me it works…. ok now keep reading to see exactly how it works.”

Comments are closed.