tags:

views:

154

answers:

6

I see examples where JavaScript code including jQuery and jslint use the notation below:

(function(){
  // do something
})();

instead of:

// do something

I first thought this is just for local scoping, i.e. creating local variables for the code block without polluting global namespace. But I've seen instances without any local variables at all too.

What am I missing here?

+7  A: 

It's about scope for functions, too - everything declared within the code block is scoped to that anonymous function only. Things are normally made public by the framework

(function($) {

  var localVarOnly = "local";

  $.fn.myCoolFunction = function() { // in the case of jquery, make this publicly available
    otherCoolFunction(); //alerts hi
    alert(localVarOnly); // alerts local
  };

  function otherCoolFunction() { // scoped to this anonymous function only
    alert('hi');
  };

})(jQuery);

otherCoolFunction(); // undefined
alert(localVarOnly); // undefined
Dan Heberden
You had to throw in jQuery didn't you :)
Sean Kinsey
Haha, well it _is_ my favorite ;)
Dan Heberden
+1  A: 

This is to create a scope that will contain all the variables declared. This is to avoid polluting the global scope and to avoid overriding already existing variables.

Take this example

(function() {
    var foo = "bar";
    var undefined = true;
    var bar = true;

    alert(foo); //bar
    if (bar == undefined) {
        alert("bar is undefined.. not!"); //will show even though we know that bar is not 'undefined'
    }

})();

var bar = true;
alert(foo) //undefined
if (bar == undefined) {
    alert("bar is undefined"); // will not be called
}

When it comes to the pattern, (function(){/*....*/})(); there is currently a debate going on at comp.lang.javascript about what to call this construct, and who should get the credit for it :)

Sean Kinsey
That's one reason and I'd already figured that out (see my question :).
ssg
Its the **only** reason.
Sean Kinsey
Are you saying that there is no purpose in putting a code block in a function if you don't use any local variables? Because if you see my question I've seen examples where this notation is used without any variables at all.
ssg
It's one of the main purposes, but not the only one. Anonymous closures are f.e. used for obfuscating/protecting specific code parts against modification from outside or to "break" closures so that composite objects (Object, Array, Functions) get really duplicated.
kishkash
Thats pretty much the same thing - scoping by definition ;)
Sean Kinsey
@ssg that is correct, if you dont define **anyting** (no variables, no functions) then there is absolutely no point in doing it.
Sean Kinsey
No it's not the same thing. When you want to really duplicate a object, in 99,9% of all cases one is going to call multiple nested anonymous functions to accomplish that. Alone this is a adequate use-case.
kishkash
@peta scoping has nothing to do with duplicating an object - you should probably read up on the spec. This I know. If you are referring to passing arguments to the invoked function then this is only creating new `references` to the same objects, references that can be replaced without disturbing the variable holding the first reference.
Sean Kinsey
@peta and about your use-case; what?
Sean Kinsey
@Sean Kinsey: Sorry, you're right. I totally confused it with reference storing of composite objects what only can be "broken" by using two anonymous closures. :)
kishkash
Do you have a reference for that? Never heard of it..
Sean Kinsey
+2  A: 

The main purpose of this (Crockford's) pattern (there are others -- in some cases more performant -- too) is to avoid the pollution of the global scope with named functions/identifiers. By doing stuff within this anonymous closure, you can write your code as you'd do inside the global scope, except that everything declared inside remains local and thus cannot be accessed/referenced from outside. Use-cases where no local variables/functions are used or "exported" (assigned to a named identifier from one of the outer scopes), might exist, but don't necessarily have to be nested within a anonymous funciton.

kishkash
+2  A: 

That syntax is to create local scope, as others have commented, but also to make the function self-executing. Note that simply creating local scope could also be accomplished like this:

var foo = function(){
   // local code
};
foo();

But if that's all you're doing, and foo has no other utility beyond calling it one time, then the anonymous, self-executing syntax simply saves you the extra var declaration:

(function(){
   // local code
})();

In frameworks that use OOP patterns, this is also the syntax used to create singletons since the function can only run once and can never be called again by external code.

bmoeskau
A: 

This came to me just after asking the question: If there is any benefit in detaching this from document.window one might choose to wrap the code in a local scope. I remember seeing "access to window object is slow" in jQuery source, don't know the details. Let me know if this is a valid point.

ssg
In the case of the anonymous function, it's running directly in the DOM and access speed wouldn't be of concern. e.g. (function() { /*do stuff*/})(); would run as fast as myObject.test = function() { /* do stuff*/ };
Dan Heberden
@ssg, don't believe everything you find in the jQuery source :) But copying the reference to a local variable will normally be faster.@Dan: what are you on about? Where did speed come into play? And how is what you said correct?
Sean Kinsey
+4  A: 

As everyone else has said, it's pretty much entirely to do with creating local scope. Another benefit is that you can use it to (for want of a better word) "rename" variables. Take for instance, how several javascript frameworks use $ as a shorthand for their main library function. If you create a closure like in your example, it doesn't matter what $ is outside, you can use it as a parameter and inside it can be whatever you want:

// out here $ might be Prototype, something else, or even undefined
(function($) {
    // in here, $ is jQuery
})(jQuery);

Another little tip for eking an extra couple of milliseconds of your script is to use this same technique to create an undefined variable. Most people think that undefined is a special keyword in javascript, but it's actually just treated as a normal variable, which you'd hope no one would define. The somewhat standard practice of checking for a undefined variable:

if (x == undefined)

...is actually rather wasteful, since it checks the entire scope chain for a variable named "undefined". To shortcut this, you can use this method:

(function($, undefined) {
    // code here
})(jQuery);  // note that there's just one parameter passed

Now that undefined is actually in a scope (with an undefined value), checking up the scope chain can stop at that point. Micro-optimisation, yes, but it doesn't hurt to know.

nickf
Regarding optimization of `undefined` variable: isn't it still faster to test for string `"undefined"` instead of comparing against a variable (with ‘coincidentally’ the same name)?
Marcel Korpel
@Marcel - I just did a test (1,000,000 iterations of both methods). Using `typeof x == "undefined"` took ~2050ms. Using `x == undefined` took ~34ms.
nickf
How did you test this? E.g., if I use [this test case](http://pastie.org/999172) in Firefox, there's hardly any difference between the two, but in Chromium `typeof x == "undefined"` is significantly faster than `typeof x == undefined`. Testing for `x == undefined` only works when `x` is defined (otherwise an error is thrown); timings hardly differ in Firefox and it is even slightly slower in Chromium than testing `typeof x == "undefined"` when `x` is defined.
Marcel Korpel
@Marcel, in that test you pasted you didn't "define" `undefined` like in my last code sample above. Changing the test so that there is a closure with a variable named `undefined` left undefined meant the code ran 55% faster on my PC (Firefox 3.6.3)
nickf
Yes, of course, that was what your second tip was all about. But it still only works when `x` is defined or explicitly set to `undefined` as an argument to the anonymous function (like the variable `undefined` in your example). A really undefined variable, like in the case I pasted, throws an error when testing `x == undefined` (“Uncaught ReferenceError: x is not defined” in Chrome and “x is not defined” in Firefox). BTW, ~34ms is not 55% faster than ~2050ms. A typo somewhere?
Marcel Korpel