tags:

views:

9890

answers:

9

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:

var functionOne = function() {
 // Some code
}

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.

+77  A: 

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

<script>

// Error
functionOne();

var functionOne = function()
{
}

</script>



<script>

// No error
functionTwo();

function functionTwo()
{
}

</script>

Edit: I forgot to mention that using the var method, your function is also scoped:

<script type="text/javascript">

function foo()
{
    var functionOne = function() { alert('hello'); }

    // No error
    functionOne();

    document.body.onclick = functionOne;
}

foo();

// Error
functionOne();

</script>

This lets you create a function and assign it to multiple event handlers without cluttering up the global namespace.

Greg
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
Thanks for the examples, that really helped.
Richard
SEXY explanation.
cLFlaVA
VERY good explaination.
Laykes
Great, now I wonder how CommonJS would parse it serverside...
Gio Borje
+40  A: 
Eugene Lazutkin
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
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
That what happens when relying on IE's JavaScript behavior. ;-) Thank you for thoroughness --- I'll update the answer.
Eugene Lazutkin
A: 

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).

Kafka
A: 
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.

kiamlaluno
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
+1  A: 

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? */} }

Sasha Firsov
There are the test to confirm: http://blog.firsov.net/2010/01/js-local-functions-anonymous-vs-named.htmlJS performance test - scope and named functions - Analytics
Sasha Firsov
+1  A: 

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.
thomasrutter
+6  A: 

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:

 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.:

 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.

CMS
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
+1  A: 

Functions are first-class objects in JavaScript. This means that they are able to be passed around as parameters, assigned to another variable or returned from another function.

In other words, when you use the syntax:

function x() {
   return "hi";
}

it is exactly equivalent to declaring a variable pointing to that function in the current scope:

var x = function() {
   return "hi";
}

You can even create a new Function object like this: (highly discouraged, just for purposes of this example)

var x = new Function("return \"hi\";");

And in all of the above cases, x would be exactly the same thing.

Note: Only when using the var keyword will the assigned variable be declared in the current scope, otherwise it will be put in global scope (usually a bad idea).

Jacob Relkin
Creating a function with the last method is just like calling `eval()` — you should avoid it unless it is much better than other solutions.
KennyTM
+1  A: 

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

var MyNamespace = {}
  MyNamespace.foo= function() {
}

or

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

Rob