alnafie
alnafie

Reputation: 10798

Javascript immediately invoked function patterns

What do you call these patterns? What is the difference between them? When would you use each? Are there any other similar patterns?

(function() {
    console.log(this);  // window
})();

(function x() {
    console.log(this);  // window
})();

var y = (function() {
    console.log(this);  // window
})();

var z = function() {
    console.log(this);  // window
}();

EDIT: I just found two more seemingly redundant ways to do this by naming the functions in the last two cases...

var a = (function foo() {
    console.log(this);  // window
})();

var b = function bar() {
    console.log(this);
}();

EDIT2: Here is another pattern provided below by @GraceShao which makes the function accessible outside the function scope.

(x = function () {
    console.log(this);  // window
    console.log(x);     // function x() {}
})();
console.log(x);         // function x() {}

// I played with this as well 
// by naming the inside function 
// and got the following:

(foo = function bar() {
    console.log(this);  // window
    console.log(foo);   // function bar() {}
    console.log(bar);   // function bar() {}
})();
console.log(foo);       // function bar() {}
console.log(bar);       // undefined

Upvotes: 14

Views: 9931

Answers (6)

Yilmaz
Yilmaz

Reputation: 49271

JavaScript in the browser is the lacks namespacing. Every piece of code runs in the global scope; therefore, internal application code or third-party dependencies can pollute the scope while exposing their own pieces of functionality. Polluting global namespace causes name collision. This name collision is very common in large projects and can be extremely harmful.

Imagine, for instance, that a third-party library instantiates a global variable called utils. If any other library, or the application code itself, accidentally overrides or alters utils, the code that relies on it will likely crash in some unpredictable way. Unpredictable side effects can also happen if other libraries or the application code accidentally invoke a function of another library meant for internal use only.

 (function () {
      // create state variables
      // make some operation
      // then return those
      const export = {
           export1: () => {},
           export2: () => {}
      }
      return exported
})()

it is used to create a private scope, exporting only the parts that are meant to be public.

Parentheses around function expressions

Why do we even need those? The reason is purely syntactical. The JavaScript parser has to be able to easily differentiate between function declarations and function expressions. If we leave out the parentheses around the function expression, and put our immediate call as a separate statement function(){}(3), the JavaScript parser will start processing it, and will conclude, because it’s a separate statement starting with the keyword function, that it’s dealing with a function declaration. Because every function declaration has to have a name (and here we didn’t specify one), an error will be thrown. To avoid this, we place the function expression within parentheses, signaling to the JavaScript parser that it’s dealing with an expression, and not a statement.

You might also see this in some projects:

+function(){}();
-function(){}();
!function(){}();
~function(){}();

This time, instead of using parentheses around the function expressions to differentiate them from function declarations, we can use unary operators: + , - , ! , and ~. We do this to signal to the JavaScript engine that it’s dealing with expressions and not statements.

Upvotes: 0

Paul
Paul

Reputation: 141829

Here are your functions again with some comments describing when/why they might be useful:

(function() {
    // Create a new scope to avoid exposing 
    // variables that don't need to be
    // This function is executed once immediately
})();

(function fact(i) {
    // This named immediately invoked function 
    // is a nice way to start off recursion
    return i <= 1 ? 1 : i*fact(i - 1);
})(10);

var y = (function() {
    // Same as the first one, but the return value 
    // of this function is assigned to y
    return "y's value";
})();

var z = function() {
    /* This is the exact same thing as above 
     (except it is assigned to z instead of y, of course).
     The parenthesis in the above example don't do anything
     since this is already an expression
    */
}();

Upvotes: 39

Ruhul Amin
Ruhul Amin

Reputation: 1779

It's time to use ES06, Here are your functions using arrow function from ES06.

 (() => {
    // Create a new scope to avoid exposing variables that don't need to be
    // This function is executed once immediately
})();

(fact = (i)=>(
  // This named immediately invoked function is a nice way to start off recursion
  i <= 1 ? 1 : i*fact(i - 1)
))(10)

const y = (() => (
    // Same as the first one, but the return value of this function is assigned to y
     "y's value"
))();

const z = (() => {
    // This is the exact same thing as above (except it's assigned to z instead of y, of course).
    // The parenthesis in the above example don't do anything since this is already an expression
})();

Upvotes: 0

Rakesh Ranjan
Rakesh Ranjan

Reputation: 1

(function() { 'use strict'; you can use this type

Why?: An IIFE-Immediately Invoked Function Expression removes variables from the global scope. This helps prevent variables and function declarations from living longer than expected in the global scope, which also helps avoid variable collisions.

Why?: When your code is minified and bundled into a single file for deployment to a production server, you could have collisions of variables and many global variables. An IIFE protects you against both of these by providing variable scope for each file.

Upvotes: 0

user166390
user166390

Reputation:

In this case they are all semantically identical. The ECMAScript specification contains the full production rules, so this is a gross simplification.

Also note that I am ignoring the named function's name (x) as the name is not used; it could be referenced within the body but since it is a FunctionExpression (via the grammar production) it would never (in a correct JS implementation) contaminate the containing scope - see the comments.

(function() {
    console.log(this);  // window
})();

(function x() {
    console.log(this);  // window
})();

var y = (function() {
    console.log(this);  // window
})();

var z = function() {
    console.log(this);  // window
}();

Reduced (the bodies are inconsequential in this case, they all "return undefined"):

(function() {})();

(function x() {})();

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

var z = function() {}();

Reduced (in the ECMAScript grammar FunctionExpression is a production rule, but here I use it to mean "an expression that is a function"):

FunctionExpression()

FunctionExpression()

var y = FunctionExpression()

var z = FunctionExpression()

Ignoring the assignment of the result (which would always be undefined) it can be seen that all forms are the same.

Happy coding.

Upvotes: 6

Grace Huang
Grace Huang

Reputation: 5679

Self invoking anonymous function. The function body will be invoked immediately.

(function() {
    console.log(this);  // window
})();

Self invoking function. The function body will be invoked immediately. You can still refer to the function x inside the function body. So when you want to execute something immediately, and then you may want to iterate it, you can just reference to it directly.

(function x() {
    console.log(this);  // window
    console.log(x);     // function x() {}
})();

The self invoking anonymous function on the right side will be invoked immediately, and the returned value will be assigned to the y. Usually it has a return value when you use this pattern, otherwise, y will be undefined.

var y = (function() {
    console.log(this);  // window
})();

IMO, it is same as the third one. The parentheses of the 3rd enclosing the function are just for making the function look like one entire thing. But the functionalities of the both are the same.

var z = function() {
    console.log(this);  // window
}();

Similar to the 2nd one, but you can reference the x outside the function scope by using:

(x = function () {
    console.log(this);  // window
    console.log(x);     // function x() {}
})();
console.log(x);         // function x() {}

Upvotes: 2

Related Questions