First I want to correct RoBorg: function abc(){}
is scoped too — the name abc
is defined in the scope where this definition is encountered. Example:
<@ class="default prettyprint">
function xyz(){
function abc(){};
// abc is defined here...
}
// ...but not here
@>
Secondly, it is possible to combine both styles:
<@ class="default prettyprint">
var xyz = function abc(){};
@>
xyz
is going to be defined as usual, abc
is undefined in all browsers but IE — do not rely on it being defined. But it will be defined inside its body:
<@ class="default prettyprint">
var xyz = function abc(){
// xyz is visible here
// abc is visible here
}
// xyz is visible here
// abc is undefined here
@>
If you want to alias functions on all browsers use this kind of declaration:
<@ class="default prettyprint">
function abc(){};
var xyz = abc;
@>
In this case both xyz
and abc
are aliases of the same object:
<@ class="default prettyprint">
console.log(xyz === abc); // prints "true"
@>
One compelling reason to use the combined style is the "name" attribute of function objects (not supported by IE). Basically when you define a function like this:
<@ class="default prettyprint">
function abc(){};
console.log(abc.name); // prints "abc"
@>
its name is automatically assigned. But when you define it like this:
<@ class="default prettyprint">
var abc = function(){};
console.log(abc.name); // prints ""
@>
its name is empty — we created an anonymous function and assigned it to some variable.
Another good reason to use the combined style is to use a short internal name to refer to itself, while providing a long non-conflicting name for external users:
<@ class="default prettyprint">
var really.long.external.scoped.name = function shortcut(n){
// let's call itself recursively:
shortcut(n - 1);
// ...
// let's pass itself as a callback:
someFunction(shortcut);
// ...
}
@>
In the example above we can do the same with an external name, but it'll be too unwieldy (and slower).
(Another way to refer to itself is to use arguments.callee
, which is still relatively long.)
Deep down JavaScript treats both statements differently. This is the function declaration:
<@ class="default prettyprint">
function abc(){}
@>
abc
here is defined everywhere in the current scope:
<@ class="default prettyprint">
// we can call it here
abc(); // works
// yet it is defined down there
function abc(){}
// we can call it again
abc(); // works
@>
This is the function expression:
<@ class="default prettyprint">
var xyz = function(){};
@>
xyz
here is defined from the point of assignment:
<@ class="default prettyprint">
// we can't call it here
xyz(); // UNDEFINED!!!
// now it is defined
xyz = function(){}
// we can call it here
xyz(); // works
@>
Function declaration vs. function expression is the real reason why there is a difference demonstrated by RoBorg.
Fun fact:
<@ class="default prettyprint">
var xyz = function abc(){};
console.log(xyz.name); // prints "abc"
@>
Personally I prefer the "function expression" declaration because this way I can control the visibility. When I define the function like that:
<@ class="default prettyprint">
var abc = function(){};
@>
I know that I defined the function locally. When I define the function like that:
<@ class="default prettyprint">
abc = function(){};
@>
I know that I defined it globally providing that I didn't define abc
anywhere in the chain of scopes. This style of definition is resilient even when used inside eval(). While this definition:
<@ class="default prettyprint">
function abc(){};
@>
depends on the context and may leave you guessing where it is actually defined, especially in the case of eval() — the answer is: it depends on browser.