59

Possible Duplicate:
JavaScript: var functionName = function() {} vs function functionName() {}

There are two possible methods for pulling out a function in Javascript:

var foo = function() { ... }

This is a bit contrived; another common pattern is:

var foo = {
   baz: 43,
   doSomething: function() {
       // ...
   }
}

versus

function foo() { 
  // ... 
}

Is there an explicit reason to prefer one or the other?

Shakespear
  • 1,280
  • 3
  • 19
  • 25
Billy ONeal
  • 97,781
  • 45
  • 291
  • 525

4 Answers4

85

It all comes down to preference to where you declare your functions; hoisting.

Function declarations and variable declarations are always moved ("hoisted") invisibly to the top of their containing scope by the JavaScript interpreter. Function parameters and language-defined names are, obviously, already there. This means that code like this:

function foo() {
    bar();
    var x = 1;
}

is actually interpreted like this:

function foo() {
    var x;
    bar();
    x = 1;
}

Notice that the assignment portion of the declarations were not hoisted. Only the name is hoisted. This is not the case with function declarations, where the entire function body will be hoisted as well.

function test() {
    foo(); // TypeError "foo is not a function"
    bar(); // "this will run!"
    var foo = function () { // function expression assigned to local variable 'foo'
        alert("this won't run!");
    }
    function bar() { // function declaration, given the name 'bar'
        alert("this will run!");
    }
}
test();

In this case, only the function declaration has its body hoisted to the top. The name 'foo' is hoisted, but the body is left behind, to be assigned during execution.

You can give names to functions defined in function expressions, with syntax like a function declaration. This does not make it a function declaration, and the name is not brought into scope, nor is the body hoisted.

foo(); // TypeError "foo is not a function"
bar(); // valid
baz(); // TypeError "baz is not a function"
bin(); // ReferenceError "bin is not defined"

var foo = function () {}; // anonymous function expression ('foo' gets hoisted)
function bar() {}; // function declaration ('bar' and the function body get hoisted)
var baz = function bin() {}; // named function expression (only 'baz' gets hoisted)

foo(); // valid
bar(); // valid
baz(); // valid
bin(); // ReferenceError "bin is not defined"

So, if your preference is to have functions hoist to the top use a function declaration otherwise use expression. I prefer the latter as I typically build object literals with methods as function expressions.

Named function expressions can be handy when errors are thrown. The console will tell you what the function is instead of stating anonymous aka stack trace.

Trevor
  • 10,371
  • 1
  • 30
  • 40
  • 4
    Just remember that function declarations in blocks is [technically invalid](http://stackoverflow.com/questions/4071292/may-function-declarations-appear-inside-statements-in-javascript), so it might be preferred to use function expressions then. – Jesse Good Apr 10 '12 at 01:22
  • 1
    Wow, it's so obvious that "function declarations" should not exist/be treated specially in javascript - they should just be an expression, like "named function expression", whose return value is ignored. – masterxilo Jun 02 '14 at 20:11
  • @JesseGood—ah yes, I mean inside *if* blocks. I'll fix that. – RobG May 18 '16 at 23:04
  • @JesseGood—function declarations inside blocks aren't "technically invalid" at all, if they were they'd throw a syntax error. There is no good reason to prefer function expressions over declarations where the two can be interchanged (noting that there are cases where function expressions are allowed but declarations aren't). – RobG May 18 '16 at 23:04
  • @RobG: Syntax errors are not the only issue. The difference can cause [semantically different programs](http://stackoverflow.com/questions/25111087/why-is-a-function-declaration-within-a-condition-block-hoisted-to-function-scope). – Jesse Good May 19 '16 at 09:09
  • @JesseGood—syntax errors aren't an issue at all. The only issue is that Mozilla unilaterally implemented function statements resulting in behaviour different to other implementations. – RobG May 19 '16 at 09:19
  • @RobG: Yes, that makes function declarations inside blocks non-portable, which is my point. – Jesse Good May 19 '16 at 09:31
  • 1
    This is an important difference often forgotten: "Named function expressions can be handy when errors are thrown. The console will tell you what the function is instead of stating anonymous aka stack trace." – Emilio Dec 01 '18 at 19:54
11

You've hit on a couple different things here, but I'll try to hit your main question first.

In general....

function() { ... } is a function expression. Syntaxically this is on the same level as 2 or [4,5]. This represents a value. So doing var foo=function(){ ... } will work as planned, every time.

function foo() { ... } is a function declaration. This might seem to do the same thing as var foo=function(){...}, but there's a small caveat. As its a declaration, it works similar to the concept of variable hoisting in JS (basically, all variable declarations are done before any expressions are evaluated).

A good example is from here:

function test() {
    foo(); // TypeError "foo is not a function"
    bar(); // "this will run!"
    var foo = function () { // function expression assigned to local variable 'foo'
        alert("this won't run!");
    }
    function bar() { // function declaration, given the name 'bar'
        alert("this will run!");
    }
}
test();

Basically variable hoisting has brought the value up to the top, so this code is equivalent (in theory) to :

function test() {
    var foo;//foo hoisted to top
    var bar=function(){//this as well
        alert("this will run!");
    }

    foo(); // TypeError "foo is not a function"
    bar(); // "this will run!"
    var foo = function () { // function expression assigned to local variable 'foo'
        alert("this won't run!");
    }
}

NB: I'd like to take this spot to say that JS interpreters have a hard time following theory, so trusting them on somewhat iffy behaviour is not recommended. Here you'll find a good example at the end of a section where theory and practice end up not working (there are also some more details on the topic of expressions vs declarations).

Fun fact: wrapping function foo() {...} in parentheses transforms it from a declaration to an expression, which can lead to some weird looking code like

(function foo() { return 1; })();// 1
foo; //ReferenceError: foo is not defined

Don't do this if you don't have a reason to, please.


Summary var foo=function(){ ... } is *sorta kinda * the same as function foo(){ ... } except that the former does what you think it does where you think it should whereas the latter does weird stuff unless you wrap it in parens, but that messes up the scope, and JS interpreters allow you to do things that are considered syntax errors in the spec so you're led to believe that wrong things are in fact right, etc....

please use function expressions( var f=function(){...} ). There's no real reason not to, especially considering you're somewhat forced to do it when you're using dot syntax.


On to the second thing you touched.....

I'm not really sure what to say, it's kinda sorta completely different from everything else about this.

var foo = {
    baz: 43,
    doSomething:function() {
        ...
    }
}

this is known as object literal syntax. JSON, which is based off of this syntax, is a pretty neat way of formatting data, and this syntax in JS is often used to declare new objects, with singleton objects for example(avoiding all the mess with declaring a function and using new ). It can also be used in the same way XML is used, and is preferred by all the cool kids...

Anyways, basically object literal syntax works like this:

{ name1: val1, .... namek:valk }

This expression is an object with certain values initialised on it. so doing var obj={ name1: val1, .... namek:valk } means that :

obj.name1==val1;
obj['name1']==val1;// x['y'] is the same thing as x.y 
...
obj.namek==valk;

So what does this have to do with our example? Basically your expression is often used to declare singleton objects. But it can also be used to declare an object prototype, so someone can later do var newObj=Object.create(foo) , and newObj will have foo as a prototype.

Look into prototypal inheritence in detail if you want to really get how useful it is. Douglas Crockford talks about it in detail in one of his many talks).

rtpg
  • 2,301
  • 14
  • 30
  • 1
    The `var foo = {...` example is not JSON syntax. It's object literal syntax. JSON's data structure notations are *based on* JavaScript's object and array literal structures, but they're not the same thing. –  Apr 10 '12 at 02:28
  • noted, I've tried to change the references to JSON properly. Do you have an example of JSON that isn't valid literal syntax , or vise-versa? – rtpg Apr 10 '12 at 02:35
  • 1
    Generally, if you're defining an object literal in JavaScript code, we don't refer to it as JSON, since the rest of the JS code makes it invalid JSON. Conversely, if we remove all the JS, and just have a standalone JSON structure like `{"foo":"bar"}` (since JSON keys must be double quoted), this doesn't constitute a valid JavaScript program. The result will be a *SyntaxError*. Also, there are some invisible characters that are allowed in JavaScript strings, but not JSON. Overall, the only connection between JS and JSON are the first two letters, and the *general* syntax of data structures. –  Apr 10 '12 at 03:20
  • Here's a [short article](http://timelessrepo.com/json-isnt-a-javascript-subset) that gives some detail. Perhaps not entirely analogous, but I think of the relationship between JSON markup and JS language (or whatever language) as being similar to the relationship between HTML markup and a DOM. One is markup that can be parsed and rendered into the other. –  Apr 10 '12 at 03:24
  • rtpg, you explained the difference well, and you made a very strong recommendation of using function expressions. However your reasons for doing are:"there's no reason not to". Someone who has a an opposing opinion would not be convinced. Only someone who already agrees with you will agree. My suggestion is to show several examples of what would be bad if someone were to using function declaration. – zumalifeguard May 02 '15 at 01:01
  • `function() foo {` or `function foo() {`? – user253751 Aug 06 '15 at 00:46
2

There are few advantages to naming functions

  • names for meta analysis. functionInstance.name will show you the name.
  • Far more importantly, the name will be printed in stack traces.
  • names also help write self documenting or literate code.

There is a single disadvantage to named functions expressions

  • IE has memory leaks for NFE

There are no disadvantages to function declarations apart from less stylistic control

Raynos
  • 156,883
  • 55
  • 337
  • 385
1

Your question really comprises of two parts, as you don't necessarily have to make your functions anonymous if they are assigned to a variable or property.

Named vs anonymous?

@Raynos highlights the main points clearly. The best part about named functions is that they will show themselves in a stack trace. Even in situations where functions are being assigned to variables/properties, it's a good idea to give your functions a name just to aid with debugging, however I wouldn't say anonymous functions are evil at all. They do serve a fine purpose:

Are anonymous functions a bad practice in JavaScript?

Function declaration vs function expression?

For that part of the question I would refer you to this question as it probably covers the topic in far more depth than I can

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

Community
  • 1
  • 1
Matt Esch
  • 21,605
  • 8
  • 47
  • 49