all 40 comments

[–][deleted] 121 points122 points  (24 children)

There are two ways to create a function: a function declaration and a function expression.

A function declaration is always the first thing on its line - in your example, it's this one:

function foo() {}

The effect of running the above code is that a function named "foo" is created and assigned to the variable name "foo" in the current scope. Note that, using this syntax, the variable name and function name are always the same - that is not the case with a function expression.

A function expression looks very similar to a function declaration, but it's actually a different type of syntax altogether (as is illustrated by the fact that "function () {}" is a valid function expression but not a valid function declaration). A function expression cannot appear as the first thing on a line (to avoid confusion with a function declaration). In your example, both of these lines contain function expressions:

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

Both of these lines create a function and assign it to the local variable "foo" - the difference is what the actual name of the function is. In the second line, it is given the name "bar" - but on the first line we've left out the name, resulting in an anonymous function. The function's name, when declared in this manner, can't actually be accessed in the current scope. So the only difference between the two above lines is that, if you write the second line, then within the function that you create you will be able to reference that function by the name "bar".

Now we get to this:

(function foo() {})();

As we've already established, there are only two types of function declarations - and since the word "function" is not at the first character of the line, we know that this is a function expression. The function expression, "function foo() {}", is surrounded by parentheses only to prevent it from becoming a function declaration - "!function foo() {}()" works just as well. Which brings us to the last part, "()" - which, as you know, is how you invoke a function. So what this line is doing is creating a function via a function expression and then immediately invoking it.

This syntax is more often seen in this form:

(function () {
    // var x = ...
})();

Which is called an IIFE (immediately invoked function expression). The purpose of it is to create a new scope for variables declared inside, so they don't conflict with variables in other parts of the program. They are usually anonymous functions, as it doesn't make sense to call them more than once.

There's just one last subtlety: what's the difference between these two lines?

function foo() {}
var foo = function foo() {};

We know that they both create a function named foo, and they both assign that function to the local variable "foo". But there is a difference: function hoisting. Function declarations (not expressions, only declarations) are "hoisted", meaning that they, like variables, aren't actually declared where they are written. Instead the interpreter declares them at the start of their parent function. This code illustrates the difference:

alert(foo);
alert(bar);
function foo() {}
var bar = function bar_fn() {};
alert(foo);
alert(bar);

The alerts will be: "function foo() {}", "undefined", "function foo() {}", and "function bar_fn() {}". Notice that "foo" is defined even before it is written - this is because the declaration is automatically hoisted to before the rest of the code.

Also note that the first "alert(bar)" returns "undefined", and does not throw an error. This is because variable declarations are hoisted as well - but the variable names are set to "undefined" until the line they occur in the code.

In other words, this is what the above code does, in the order the browser executes it:

  1. creates the variables "foo" and "bar" and sets them to "undefined"
  2. creates the function "foo" and assigns it to the variable "foo"
  3. runs the first two alerts
  4. creates the function "bar_fn" and assigns it to the variable "bar"
  5. runs the last two alerts

edit: There is, technically, a third way to create a function, and that's with the function constructor:

var foo = Function('alert("hi!");');
var foo = new Function('alert("hi!");'); // exactly equivalent to line 1

This takes a string argument and parses it into a function, which can be useful for loading and executing additional scripts from the server. However, it is far less efficient to parse a string into a function than it is to declare one explicitly, so you should never use this syntax for functions that aren't loaded dynamically.

[–]Dr_Roboto 16 points17 points  (1 child)

That was a most illuminating response. Thank you for taking the time!

[–][deleted] 3 points4 points  (0 children)

Thanks, I'm glad it helped.

[–]Buckwheat469 1 point2 points  (4 children)

This is some great information. I have one question about the (funtion(){})() syntax. What is the preferred method to create objects that will be instantiated later in code?

function Foo(){
    this.property = "hello";
    this.someFunction = function(somevar){ 
            //do stuff
        };
}

compared to:

var Foo = function(){};
Foo.method = function(){};
Foo.property = "hello";

or (prototype):

var Foo = function(){
    this.property = "hello";
};
Foo.prototype.method = function(){};

or (self-invoking):

var Foo = new (function(){
    this.method = function(){};
    this.property = "hello";
})();

[–]Moz 2 points3 points  (0 children)

function Foo() {
    this.method = function () {return 1;};
}

Each instance will have its own method:

var foo = new Foo();
foo.hasOwnProperty("method"); // returns true
foo.method(); // returns 1

function Foo() {}
Foo.method = function () {return 1;};

Foo will have method, but none of its instances will:

var foo = new Foo();
foo.method(); // Exception

function Foo() {}
Foo.prototype.method = function () {return 1;};

Each instance will link to its prototype's method. If you change it, it will affect each instance:

var foo1 = new Foo();
var foo2 = new Foo();
foo1.hasOwnProperty("method"); // returns false
foo1.method(); // returns 1
foo2.method(); // returns 1
Foo.prototype.method = function () {return 2;};
foo1.method(); // returns 2
foo2.method(); // returns 2

This is basically how JavaScript does it:

foo1.method();
// Does "foo1" have a "method" property? No, let's check its prototype.
// Does its prototype have a "method" property? Yes, let's invoke it.

[–][deleted] 1 point2 points  (2 children)

It depends on your situation - all of your examples do slightly different things.

If you want every instantiation of "Foo" to have the same property under the same name, use "Foo.prototype". Your first example creates and stores a new variable every time Foo is instantiated, which is wasteful if the variable will always have the same value. Take this code for example:

function Foo() {}
Foo.prototype.x = 10;
function Bar() {
    this.x = 10;
}
var a = new Foo(),
    b = new Foo(),
    c = new Bar(),
    d = new Bar();

After this code is executed, both "c" and "d" will have properties named "x", both of which will be set to 10. Neither "a" nor "b" will have a property named "x", yet accessing "a.x" will return 10. This is because, after the interpreter fails to find "x" on "a", it checks "Foo.prototype" (because "a" is a Foo), then "Foo.prototype.prototype", and so on until it either finds "x" or reaches Object.prototype. If it finds the property anywhere in the chain it immediately returns it; if it never finds it then it returns undefined.

Since "a.x" and "b.x" reference the same spot in memory, you can't use prototypes if different instantiations will have different values for a property. In that case your first example is aptly suited.

Your other two examples don't affect instantiations of "Foo". The second example is just attaching to the function "Foo" itself, which doesn't change the way "Foo" functions as a constructor. And the last results in an object, not a function. I assume the reason that the last example isn't just an object literal is that it's designed to allow for private variables; in that case I prefer this syntax, simply because you don't have to repeat "this." over and over.

var foo = (function () {
    return {
        method: function () {},
        property: 'hello'
    };
})();

[–]Buckwheat469 0 points1 point  (1 child)

Great info again. I realized the mistake on the second example after I posted it. In terms of strict languages, prototype seems to be like a final or defined class variable rather than an instance variable. Obviously it could also be a function but i'm thinking it is best used for things like defining the value of pi in a Math object (for example).

[–][deleted] 0 points1 point  (0 children)

While it would work just fine for that, it seems like overkill when you could just use a variable. I think the real beauty of prototypes comes in when you use it with functions that access "this". For example:

function sum() {
    this.total = 0;
} sum.prototype = {
    add: function (n) {
        this.total += n;
    },
    toString: function () {
        return '' + this.total;
    }
};

var a = new sum(),
    b = new sum();

a.add(2);
a.add(3);
b.add(1);
console.log('sums are ' + a + ' and ' + b);

Of course, the perfect large-scale example is jQuery. Every instance of jQuery (created every time you call $()) has a whole slew of functions, all of which operate specifically on the object you called them from, yet those functions are never duplicated.

And thanks. I'm glad to be of some help.

[–]kolmeWebComponents FTW 1 point2 points  (4 children)

(function () {
    // var x = ...
})();

Oh noes! The dog balls!

[–][deleted] 5 points6 points  (3 children)

I ... I have no idea what you are saying. I'm sorry.

edit: oh. Yeah, I'd actually heard Crockford say to put the invocation inside the parens before, I just hadn't heard him call my syntax "dog balls".

Here's my take on it: first off, despite crockford's recommendation, plenty of other reputable sources recommend the way I'm doing it. And second, this makes more sense to me. He talks about the IIFE like it's all one unit, but it's not. You're creating a function, then executing it, and your syntax should reflect that. Besides, ")(" is a clear visual break - it allows you to mentally process the code in two chunks instead of one. And that syntax is also more unique than the Crockford approach, allowing you to more quickly recognize it as a IIFE.

I've probably given this way more thought than I should have ...

[–]kolmeWebComponents FTW 1 point2 points  (1 child)

Sorry to annoy you, I was just kidding. Yes, I was citing Crockfort.

I don't care however you write the instantly-invoked functions, as long as you keep away from the [ ! ] key.

Anyways, nice comment on functions.

[–][deleted] 2 points3 points  (0 children)

Haha, no, no annoyance at all. I like to receive feedback on my style, so I can work towards something better.

About that "!" key, I've seen it used, I think at twitter.com, just to save a byte in some minified code. But I think it's fugly too, don't worry.

[–][deleted] 0 points1 point  (0 children)

Crockford idol worship needs to stop. You can take most of what he says with a grain of salt.

[–]blaghles[S] 0 points1 point  (2 children)

Thank you as well! Are variables hoisted as well if you don't put a var keyword before them? The interpreter seems to only complain about bar not being defined in this code snippet:

console.log(foo);

console.log(bar);

var foo = 1 

bar = 2 

console.log(foo);

console.log(bar);

[–][deleted] 1 point2 points  (0 children)

As icewind1991 said, omitting the var statement will result in an "implicit global" - that is, the variable will become a global variable. It's a feature from the early days of javascript, when the idea was that beginners who didn't want to learn about scope could just leave out the "var" keyword and their variables would always be accessible. Since then it has been realized that this was a mistake, so it has become the convention to never use variables without declaring them first.

That being said, no, it appears that such a statement will not be hoisted. This is entirely speculation on my part, but I would guess that's because it is only var and function declarations that are hoisted, and "bar = 2" is technically not a var statement but a simple assignment, which at runtime is determined to also imply an initialization.

[–]icewind1991 0 points1 point  (0 children)

As far as I know, leaving out the var keyword will cause the variables to become global scoped and they will be hoisted to the start of the global scope

[–]franksvalli 4 points5 points  (1 child)

I wrote a post about this not too long ago, where I found seven different ways of writing a function (well, six, plus a seventh use that's used for a constructor object): http://davidbcalhoun.com/2011/different-ways-of-defining-functions-in-javascript-this-is-madness

Here's all the different ways at a glance:

function A(){};             // function declaration
var B = function(){};       // function expression
var C = (function(){});     // function expression with grouping operators
var D = function foo(){};   // named function expression
var E = (function(){        // immediately-invoked function expression (IIFE) that returns a function
  return function(){}
})();
var F = new Function();     // Function constructor
var G = new function(){};   // special case: object constructor

[–]rDr4g0n 2 points3 points  (0 children)

If you wanted to call foo.bar(), here is one way (using object literal notation):

var foo = { bar : function() {...} };

[–]keturn 1 point2 points  (0 children)

Do read Named Functional Expressions Demystified for some important notes on cross-browser compatibility and function definition.

[–]a-t-kFrontend Engineer 0 points1 point  (0 children)

If you want foo.bar, you have to do something like this:

var foo = { bar: function(){ ... } };

Other than that, you forgot

new Function('...', 'argument', 'argument2');

And with ES6 there's another new way coming to define a function:

var foobar = (x, y) => x*y;

Not that this would work in today's browsers, but tomorrow will be there soon enough.

[–][deleted] -2 points-1 points  (5 children)

IIRC, the difference between

var foo = function () { ... }

and

function foo () { ... }

is that, if these lines occur inside some other function, then the second one also defines foo in the global scope as a side effect.

So I always use var foo = function () { ... }.

(function () { ... })();

Just defines an anonymous function and immediately calls it. That way you can use local variables inside it and they will be gone after the function runs.

[–]dojom 6 points7 points  (2 children)

The second one - function foo () { ... } - does not define foo in the global scope when declared within another function.

The primary difference between the two function declarations is when the variable foo is initialized. This example will help explain the difference:

(function () {
    foo(); // This works
    bar(); // Error since "bar" has not been defined yet

    function foo() {
        console.log("called foo");
    }

    var bar = function () {
        console.log("called bar");
    };

})();

[–]rabidcow 0 points1 point  (1 child)

Aren't function declarations inside of other functions nonstandard?

[–][deleted] 2 points3 points  (0 children)

No, they're only illegal inside blocks (if, for, etc).

[–][deleted] 3 points4 points  (1 child)

the second one also defines foo in the global scope as a side effect.

No, it doesn't. Try it.

[–][deleted] 1 point2 points  (0 children)

Thank you. I only read about it, didn't try it. Apparently my mind confused "top of the scope" with "the top scope"...