Saturday, 27 April 2013

Immediately-invoked function expression

An immediately-invoked function expression (or IIFE, pronounced "iffy") is a JavaScript design pattern which produces block scoping using JavaScript's function scoping. Immediately-invoked function expressions can be used to avoid variable hoisting from within blocks, protect against polluting the global environment and simultaneously allow public access to methods while retaining privacy for variables defined within the function. This pattern has been referred to as a self-executing anonymous function,[1] but Ben Alman introduced the term IIFE as a more semantically accurate term for the pattern.[2][3]


Immediately-invoked function expressions may be written in a number of different ways,[4] although a common convention is to enclose both the function expression and invokation in parentheses.[5][6]
  /* code */ 


Key to understanding design patterns such as immediately-invoked function expressions is to realize JavaScript has function scope (but not block scope) and passes values by reference inside a closure.[7]

[edit]Evaluation context

A lack of block scope means that variables defined inside, for example, a for loop will have their definition "hoisted' to the top of the enclosing function. Evaluating a function which depends on variables modified by the outer function (including by iteration) can be difficult. We can see this without a loop if we update a value between defining and invoking the function.[8]
var v, getValue;
getValue = function() { return v; };
v = 2;
getValue(); // 2
While the result may seem obvious when updating v manually, it can produce unintended results when getValue() is defined inside a loop.
var v, getValue;
v = 1;
getValue = (function(v) {
  return function() {return v;};
v = 2;
getValue(); //1
Here the function passes v as an argument and is invoked immediately, preserving the inner function's execution context.[9]
David Herman's Effective JavaScript contains an example illustrating the problems of evaluation context inside loops.[10] While Herman's example is deliberately convoluted it arises directly from the same lack of block scope.[11]

Establishing private variables and accessors

IIFEs are also useful for establishing private methods for accessible functions while still exposing some properties for later use.[12] The following example comes from Alman's post on IIFEs.[2]
var counter = (function(){
  var i = 0;
  return {
    get: function(){
      return i;
    set: function( val ){
      i = val;
    increment: function() {
      return ++i;
// 'counter' is an object with properties, which in this case happen to be
// methods.
counter.get(); // 0
counter.set( 3 );
counter.increment(); // 4
counter.increment(); // 5
If we attempt to access counter.i from the global environment, it will be undefined as it is enclosed within the invoked function and is not a property of counter. Likewise, if we attempt to access i it will result in an error as we have not declared i in the global environment.


No comments:

Post a Comment