3

I've seen experts using below to declare a function:

(function () {
  function f(n) {
        // Format integers to have at least two digits.
        return n < 10 ? '0' + n : n;
    }
  //etc

}());

e.g. https://github.com/douglascrockford/JSON-js/blob/master/json.js

Could someone help me understand when should we use above pattern and how do we make use of it?

Thanks.

Nil Pun
  • 17,035
  • 39
  • 172
  • 294
  • 1
    The basic idea is: when you don't want that function to be visible in the global namespace for other code - i.e. to keep it private and / or to avoid polluting the global namespace. – Rup Jun 05 '13 at 12:05
  • related: [Immediately-Invoked Function Expression (IIFE) vs not](http://stackoverflow.com/q/14317998). – Felix Kling Jun 05 '13 at 12:16

3 Answers3

2

Well, since ECMA6 hasn't arrived yet, functions are about the best way to create scopes in JS. If you wrap a variable declaration of sorts in an IIFE (Immediately Invoked Function Expression), that variable will not be created globally. Same goes for function declarations.
If you're given the seemingly daunting task of clearing a script of all global variables, all you need to do is wrap the entire script in a simple (function(){/*script here*/}());, and no globals are created, lest they are implied globals, but that's just a lazy fix. This pattern is sooo much more powerful.

I have explained the use of IIFE in more detail both here, here and here

The basic JS function call live-cycle sort of works like this:

f();//call function
 ||
 ====> inside function, some vars are created, along with the arguments object
        These reside in an internal scope object
     ==> function returns, scope object (all vars and args) are GC'ed

Like all objects in JS, an object is flagged for GC (Garbage Collection) as soon as that object is not referenced anymore. But consider the following:

var foo = (function()
{
    var localFoo = {bar:undefined};
    return function(get, set)
    {
        if (set === undefined)
        {
            return localFoo[get];
        }
        return (localFoo[get] = set);
    }
}());

When the IIFE returns, foo is assigned its return value, which is another function. Now localFoo was declared in the scope of the IIFE, and there is no way to get to that object directly. At first glance you might expect localFoo to be GC'ed.
But hold on, the function that is being returned (and assigned to foo still references that object, so it can't be gc'ed. In other words: the scope object outlives the function call, and a closure is created.

The localFoo object, then, will not be GC'ed until the variable foo either goes out of scope or is reassigned another value and all references to the returned function are lost.

Take a look at one of the linked answers (the one with the diagrams), In that answer there's a link to an article, from where I stole the images I used. That should clear things up for you, if this hasn't already.

An IIFE can return nothing, but expose its scope regardless:

var foo = {};
(function(obj)
{
    //obj references foo here
    var localFoo = {};
    obj.property = 'I am set in a different scope';
    obj.getLocal = function()
    {
        return localFoo;
    };
}(foo));

This IIFE returns nothing (implied undefined), yet console.log(foo.getLocal()) will log the empty object literal. foo itself will also be assigned property. But wait, I can do you one better. Assume foo has been passed through the code above once over:

var bar = foo.getLocal();
bar.newProperty = 'I was added using the bar reference';
bar.getLocal = function()
{
    return this;
};
console.log(foo.getLocal().newProperty === bar.newProperty);
console.log(bar ==== foo.getLocal());
console.log(bar.getLocal() === foo.getLocal().getLocal());
//and so on

What will this log? Indeed, it'll log true time and time again. Objects are never copied in JS, their references are copied, but the object is always the same. Change it once in some scope, and those changes will be shared across all references (logically).
This is just to show you that closures can be difficult to get your head round at first, but this also shows how powerful they can be: you can pass an object through various IIFE's, each time setting a new method that has access to its own, unique scope that other methdods can't get to.

Note
Closers aren't all that easy for the JS engines to Garbage Collect, but lately, that's not that big of an issue anymore.
Also take your time to google these terms:

IIFE's can be named functions, too, but then the only place where you can reference that function is inside that function's scope:

(function init (obj)
{
    //obj references foo here
    var localFoo = {};
    obj.property = 'I am set in a different scope';
    obj.getLocal = function()
    {
        return localFoo;
    };
    if (!this.wrap)
    {//only assign wrap if wrap/init wasn't called from a wrapped object (IE foo)
        obj.wrap = init;
    }
}(foo));
var fooLocal = foo.getLocal();
//assign all but factory methods to fooLocal:
foo.wrap(fooLocal);
console.log(fooLocal.getLocal());//circular reference, though
console.log(init);//undefined, the function name is not global, because it's an expression

This is just a basic example of how you can usre closures to create wrapper objects...

Community
  • 1
  • 1
Elias Van Ootegem
  • 74,482
  • 9
  • 111
  • 149
1

Well the above pattern is called the immediate function. This function do 3 things:-

The result of this code is an expression that does all of the following in a single statement:

  1. Creates a function instance
  2. Executes the function
  3. Discards the function (as there are no longer any references to it after the statement has ended)

This is used by the JS developers for creating a variables and functions without polluting the global space as it creates it's own private scope for vars and functions.

In the above example the function f(){} is in the private scope of the immediate function, you can't invoke this function at global or window scope.

pvnarula
  • 2,771
  • 18
  • 22
  • immediately invoked function expression to be precise. – Christoph Jun 05 '13 at 12:13
  • one and a same thing. Usually it is called immediate functions. – pvnarula Jun 05 '13 at 12:14
  • There is no standard name. In earlier days it was called "immediate function" but now the term IIFE is becoming more popular, probably due to this article: http://benalman.com/news/2010/11/immediately-invoked-function-expression/. – Felix Kling Jun 05 '13 at 12:18
  • @pvnarula: The IIFE needn't be GC'ed: if it's named, and is referenced in its function body, it can't be GC'ed – Elias Van Ootegem Jun 05 '13 at 12:47
1

Browser-based JavaScript only has two scopes available: Global and Function. This means that any variables you create are in the global scope or confined to the scope of the function that you are currently in.

Sometimes, often during initialization, you need a bunch of variables that you only need once. Putting them in the global scope isn't appropriate bit you don't want a special function to do it.

Enter, the immediate function. This is a function that is defined and then immediately called. That's what you are seeing in Crockford's (and others') code. It can be anonymous or named, without defeating the purpose of avoiding polluting the global scope because the name of the function will be local to the function body.

It provides a scope for containing your variables without leaving a function lying around. Keeps things clean.

Dancrumb
  • 26,597
  • 10
  • 74
  • 130
  • IIFE's can be named functions, too – Elias Van Ootegem Jun 05 '13 at 12:45
  • They can, but that kind of defeats the purpose. – Dancrumb Jun 05 '13 at 13:10
  • 1
    No it doesn't, I've added a (bad) example at the bottom of my answer: it's still a function expression, only now it's a named function expression. This way, you can still reference the called function expression in strict mode (where `arguments.callee` throws an error). You can use this technique to create a wrapper method for a single object... jQuery does somethign similar: `$ instanceof jQuery` is true, as is `$({}) instanceof jQuery`, but whereas `$(window)` works, `$({})(window)` or `$({}).(window)` doesn't – Elias Van Ootegem Jun 05 '13 at 13:59
  • @EliasVanOotegem well, well - I didn't realise that. Found the reference for the [`function` operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/function?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FOperators%2Ffunction) that explains that. Thanks for the info - I'll update my answer. – Dancrumb Jun 05 '13 at 14:49