返回列表

Javascript: var functionName = function() {} vs function functionName() {}

默认分类 2011-05-18 08:36:41

转载:http://stackoverflow.com/questions/336859/javascript-var-functionname-function-vs-function-functionname

Javascript: var functionName = function() {} vs function functionName() {}

I've recently started maintaining someone else's JavaScript code. I'm fixing bugs, adding features and also trying to tidy up the code and make it more consistent.

The previous developer uses two ways of declaring functions and I can't work out if there is a reason behind it, or not.

The two ways are:

<@ class="default prettyprint">var functionOne = function() {
// Some code
}
<@ class="default prettyprint">function functionTwo() {
// Some code
}

What are the reasons for using these two different methods and what are the pros and cons of each? Is there anything that can be done with one method that can't be done with the other?

Thanks for your help.

link|edit|flag

5  
permadi.com/tutorial/jsFunc/index.html is very good page about javascript functions uzay95 Apr 9 '10 at 11:51
1  
Related is this excellent article on Named Function Expressions. Phrogz Apr 21 at 21:30
up vote 127 down vote accepted

The difference is that functionTwo is defined at parse-time for a script block, whereas functionOne is defined at run-time. For example:

<@ class="default prettyprint"><script>
// Error
functionOne
();
var functionOne = function()
{
}
</script>
<script>
// No error
functionTwo
();
function functionTwo()
{
}
</script>
link|edit|flag
2  
Thanks for your answer. That helps me understand how they both work. I still need to understand in what circumstances you'd use the two different approaches and what the pros/cons of both are. Richard Dec 3 '08 at 11:42
Thanks for the examples, that really helped. Richard Dec 3 '08 at 12:01
5  
SEXY explanation. cLFlaVA Dec 18 '08 at 19:33
VERY good explaination. Laykes Feb 23 '10 at 22:05
Great, now I wonder how CommonJS would parse it serverside... Gio Borje Aug 31 '10 at 18:20
show 2 more comments

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.

link|edit|flag
I refer to RoBorg but he is nowhere to be found. Simple: RoBorg === Greg. That's how history can be rewritten in the age of internet. ;-) Eugene Lazutkin Jul 26 '09 at 2:52
2  
var xyz = function abc(){}; console.log(xyz === abc); All browsers I've tested (Safari 4, Firefox 3.5.5, Opera 10.10) gives me "Undefined variable: abc". NV Dec 3 '09 at 17:43
2  
That what happens when relying on IE's JavaScript behavior. ;-) Thank you for thoroughness --- I'll update the answer. Eugene Lazutkin Dec 3 '09 at 19:30
+1 for shortcut - that could be very useful. Renesis yesterday

Speaking about the global context, both, the var statement and a FunctionDeclaration at the end will create a non-deleteable property on the global object, but the value of both can be overwritten.

The subtle difference between the two ways is that when the Variable Instantiation process runs (before the actual code execution) all identifiers declared with var will be initialized with undefined, and the ones used by the FunctionDeclaration's will be available since that moment, for example:

<@ class="default prettyprint"> alert(typeof foo); // 'function', it's already available
alert
(typeof bar); // 'undefined'
function foo () {}
var bar = function () {};
alert
(typeof bar); // 'function'

The assignment of the bar FunctionExpression takes place until runtime.

A global property created by a FunctionDeclaration can be overwritten without any problems just like a variable value, e.g.:

<@ class="default prettyprint"> function test () {}
test
= null;

Another obvious difference between your two examples is that the first function doesn't have a name, but the second has it, which can be really useful when debugging (i.e. inspecting a call stack).

About your edited first example (foo = function() { alert('hello!'); };), it is an undeclared assignment, I would highly encourage you to always use the var keyword.

With an assignment, without the var statement, if the referenced identifier is not found in the scope chain, it will become a deleteable property of the global object.

Also, undeclared assignments throw a ReferenceError on ECMAScript 5 under Strict Mode.

A must read:

Note: This answer has been merged from another question, in which the major doubt and misconception from the OP was that identifiers declared with a FunctionDeclaration, couldn't be overwritten which is not the case.

link|edit|flag
I did not know that functions could be overwritten in JavaScript! Also, that parse order is the big selling point for me. I guess I need to watch how I create functions. Xeoncross Aug 8 '10 at 19:43

The two code snippets you've posted there will, for almost all purposes, behave the same way.

However, the difference in behaviour is that with the first variant, that function can only be called after that point in the code.

With the second variant, the function is available to code that runs above where the function is declared.

This is because with the first variant, the function is assigned to the variable foo at run time. In the second, the function is assigned to that identifier foo at parse time.

More technical info

Javascript has three ways of defining functions.

  1. Your first snippet shows a function expression. This involves using the "function" operator to create a function - the result of that operator can be stored in any variable or object property. The function expression is powerful that way. The function expression is often called an "anonymous function" because it does not have to have a name,
  2. Your second example is a function declaration. This uses the "function" statement to create a function. The function is made available at parse time and can be called anywhere in that scope. You can still store it in a variable or object property later.
  3. The third way of defining a function is the "Function()" constructor, which is not shown in your original post. It's not recommended to use this as it works the same way as eval(), which has its problems.
link|edit|flag

In terms of code maintenance cost named functions are more preferable:

  • independent from place where they are declared( but still limited by scope).
  • More resistant to mistakes like conditional initialization.(You are still able to override if wanted to).
  • The code becomes more readable by allocating local functions separately of scope functionality. Usually in the scope the functionality goes first, followed by declarations of local functions.
  • in debugger you will clearly see on call stack the function name instead of "anonymous/evaluated" function.

I suspect more PROS for named functions are follow. And what is listed as advantage of named functions is disadvantage for anonymous ones.

Historically anonymous functions appeared from inability of JS as language to list members with named functions:

{ member:function(){/* how to make this.member a named function? */} }

link|edit|flag
1  
There are the test to confirm: blog.firsov.net/2010/01/… JS performance test - scope and named functions - Analytics Sasha Firsov Feb 4 '10 at 0:45

An important reason is to add one and only one variable as the "Root" of your namespace...

<@ class="default prettyprint">var MyNamespace = {}
MyNamespace.foo= function() {
}

or

<@ class="default prettyprint">var MyNamespace {
foo
: function() {
},
...
}

There are many techniques for namespacing. Its become more important with the plethora of JavaScript modules available.

Also see http://stackoverflow.com/questions/881515/javascript-namespace-declaration

link|edit|flag

Other commenters have already covered the semantic difference of the two variants above. I wanted to note a stylistic difference: Only the "assignment" variation can set a property of another object.

I often build javascript modules with a pattern like this:

<@ class="default prettyprint">(function(){
var exports = {};
function privateUtil() {
...
}
exports
.publicUtil = function() {
...
};
return exports;
})();

With this pattern, your public functions will all use assignment, while your private functions use declaration.

(Note also that assignment should require a semicolon after the statement, while declaration prohibits it.)

link|edit|flag

In computer science terms, we are talking about anonymous functions and named functions. I think the most important difference is that an anonymous function is not bound to an name, hence the name anonymous function. In Javascript it is a first class object dynamically declared at runtime.

For more informationen on anonymous functions and lambda calculus, Wikipedia is a good start (http://en.wikipedia.org/wiki/Anonymous_function).

link|edit|flag
<@ class="default prettyprint">function name() {
// …
}

is syntax sugar, as the JavaScript parser creates a property that attaches to the call object if the function is defined inside another function, and to the global object in the other cases; as it is the parser to do that, I think the term "syntax sugar" is correct.

link|edit|flag
1  
Well it's not just sugar: by doing the declaration that way, the name can be used inside the function if you need to recurse. It's kind-of like "letrec" in Scheme/Lisp. Pointy Feb 8 '10 at 17:09