javascript-notes

Take notes from this post Immediately-Invoked Function Expression(IIFE)

  1. Function declaration & function expression
    Now, whether you define a function like function foo(){} or var foo = function(){}, what you end up with is an identifier for a function, that you can invoke by putting parens (parentheses, ()) after it, like foo().

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    // Because a function defined like so can be invoked by putting () after
    // the function name, like foo(), and because foo is just a reference to
    // the function expression `function() { /* code */ }`...

    var foo = function(){ /* code */ }

    // ...doesn't it stand to reason that the function expression itself can
    // be invoked, just by putting () after it?

    function(){ /* code */ }(); // SyntaxError: Unexpected token (

    As you can see, there’s a catch. When the parser encounters the function keyword in the global scope or inside a function, it treats it as a function declaration (statement), and not as a function expression, by default. If you don’t explicitly tell the parser to expect an expression, it sees what it thinks to be a function declaration without a name and throws a Sounters the function keyword in the global scope or inside a funct)

  2. functions, parens, and SyntaxErrors
    Interestingly enough, if you were to specify a name for that function and put parens immediately after it, the parser would also throw a SyntaxError, but for a different reason. While parens placed after an expression indicate that the expression is a function to be invoked, parens placed after a statement are totally separate from the preceding statment, and are simply a grouping operator (used as a means to control precedence of evaluation).

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18

    // While this function declaration is now syntactically valid, it's still
    // a statement, and the following set of parens is invalid because the
    // grouping operator needs to contain an expression.

    function foo(){ /* code */ }(); // SyntaxError: Unexpected token )

    // Now, if you put an expression in the parens, no exception is thrown...
    // but the function isn't executed either, because this:

    function foo(){ /* code */ }( 1 );

    // Is really just equivalent to this, a function declaration followed by a
    // completely unrelated expression:

    function foo(){ /* code */ }

    ( 1 );
  3. The solution: Immediately-Invoked Function Expression (IIFE)
    Fortunately, the SyntaxError ‘fix’ is simple. The most widely accepted way to tell the parser to expect a function expression is just to wrap it in parens, because in JavaScript, parens can’t contain statements. At this point, when the parser encounters the function keyword, it knows to parse it as a function expression and not a function declaration.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32

    // Either of the following two patterns can be used to immediately invoke
    // a function expression, utilizing the function's execution context to
    // create "privacy."

    (function(){ /* code */ }()); // Crockford recommends this one
    (function(){ /* code */ })(); // But this one works just as well

    // Because the point of the parens or coercing operators is to disambiguate
    // between function expressions and function declarations, they can be
    // omitted when the parser already expects an expression (but please see the
    // "important note" below).

    var i = function(){ return 10; }();
    true && function(){ /* code */ }();
    0, function(){ /* code */ }();

    // If you don't care about the return value, or the possibility of making
    // your code slightly harder to read, you can save a byte by just prefixing
    // the function with a unary operator.

    !function(){ /* code */ }();
    ~function(){ /* code */ }();
    -function(){ /* code */ }();
    +function(){ /* code */ }();

    // Here's another variation, from @kuvos - I'm not sure of the performance
    // implications, if any, of using the `new` keyword, but it works.
    // http://twitter.com/kuvos/status/18209252090847232

    new function(){ /* code */ }
    new function(){ /* code */ }() // Only need parens if passing arguments
  4. First class
    something is first-class if it:

  • can be stored in variables and data structures
  • can be passed as a parameter to a subroutine
  • can be returned as the result of a subroutine
  • can be constructed at runtime
  • has intrinsic identity (independent of any given name)

Closure example

1
2
3
4
5
6
7
function Person(name) {
return [function(newName) {
name = newName;
}, function() {
return name;
}];
}

  1. Closure
    The important thing to realise is that a closure actually remembers its environment rather than its free variables, so if you define a new variable in the environment of the closure after the closure’s definition, it will be accessible inside the closure.