[Javascript] defining functions before they're called

And Clover and-babble at doxdesk.com
Mon Aug 24 18:49:51 CDT 2009


Paul Novitski wrote:

> where's the rationale for the declare-before-you-call scripting style?
> I think it has nothing to do with JavaScript functionality and has arisen 
> because function source order matters [...] other programming languages

Well, yes... but it also makes a kind of sense. Program execution order 
is top-to-bottom in JavaScript, so in you would not expect to be able to 
refer to something you haven't defined yet.

Some static progamming languages allow forward-declaration by treating 
functions as a completely different namespace, not interacting with the 
run-time (variable) namespace at all. But that's not how JavaScript does 
it; JS functions are first-class objects, whose references are stored in 
perfectly normal variables.

The trick is: in JavaScript, the 'function' statement is magic.

When a block* is entered, the first thing it does is parse all the 
syntax in the block. Then it looks for 'function' statements and lets 
those run to define their functions first, before executing the rest of 
the block. So if you write:

     var x= alert;
     function x(s) {
         alert('hello');
     };
     x('bye');

the JS interpreter internally re-orders that into:

     var x;
     function x(s) {
         alert('hello');
     };
     x= alert;
     x('bye');

and hence you get 'bye', not 'hello' as you might have expected. The 
ECMAScript-262 standard explains this in section 10.1.3. Well I say 
'explains', but this is ECMAScript we're talking about, a document that 
makes absolutely no concessions to clarity.

This only applies to the function statement, and not the function 
expression! So if you changed the first example in a seemingly trivial way:

     var x= alert;
     x= function x(s) {
         alert('hello');
     };
     x('bye');

you now have 'hello' instead of 'bye'!

*: what's a block, in this context? Well, a script file, a script 
element, an inline event handler, a function body, a condition or 
loop... for example this:

     var x= alert;
     if (true) {
         function x(s) {
             alert('hello');
         };
     }
     x('bye');

keeps the definition of the function inside the 'if' instead of 
reordering it out before the 'alert' assignment. So you get 'hello'.

For a dynamic scripting language this is all really incredibly spooky 
and confusing; I can't think of another language that does anything like 
this. It's another in the long-running series of JavaScript Strangenesses.

So, back to the question. Should you rely on forward-declaration in 
JavaScript? Well... if you are reassigning and passing around 
functions/methods as objects, then probably you shouldn't because the 
order-of-execution is then not what it looks like and you'll get weird 
errors.

If you are treating them purely as classic static functions, you can 
probably get away with it. But even in this case you have to be careful 
to keep them in the same block; put an if round them, or split the 
script element into two, and they'll suddenly stop working.

All in all I would probably avoid it. In any case, it's very rarely 
actually useful

-- 
And Clover
mailto:and at doxdesk.com
http://www.doxdesk.com/




More information about the Javascript mailing list