IIFE – Immediately Invoked Function Expressions

Code Morning!

This is the first blog post in the series of two posts on managing scope in JavaScript. I always say that variables and functions created on global scope are dangerous due to the possibility of being overridden from other parts of the application. This might not be the problem in a small side project where you and probably one of your buddy are showcasing your JavaScript skills by making some cool stuffs, this will certainly be a problem in a real project with many people working on different JavaScript files. We will first understand what an IIFE is and will later discuss a real world example with and without IIFE.

Immediately Invoked Function Expressions (IIFE, pronounced iffy)

An IIFE is an anonymous function contained within a pair of parenthesis and is invoked immediately. The pair of parenthesis creates a local scope for all the code inside of it and makes the anonymous function a function expression. This justifies the name “Immediately Invoked Function Expression”. If you are not familiar with function expressions then I will encourage you to read my post Understand functions in JavaScript.

A typical IIFE looks like this.

(function() {
    // Your awesome code here
}());

Some people also write it like this.

(function() {
    // Your awesome code here
})();

I prefer the first style and that’s what Douglas Crockford suggests. So all my explanations will be based on the first style.

The outermost pair of parenthesis turns everything inside of it to an expression because parentheses can’t contain JavaScript statements. The other pair of parentheses after function definition invokes the function immediately. Let’s look at an example.

(function() {
    alert("I created my first IIFE today");
}());

The function above will be invoked automatically and shows the message in a message box. We will try to understand this IIFE in bits and pieces. Let’s start with writing the function you want to execute.

function() {
   alert("I created my first IIFE today");
}

This is an anonymous function for which JavaScript will report an error because this anonymous function syntax is not valid. But we can live with that for the moment as our IIFE is not completed yet. Now we will add a pair of parenthesis in the end of the function body to make it invoke immediately.

function() {
   alert("I created my first IIFE today");
}()

The last step is to wrap everything in another pair of parenthesis to make this a function expression.

(function() {
    alert("I created my first IIFE today");
}());

Any variables or functions defined within IIFE block are local to the block and it’s not possible for any code outside this scope to change them.

(function() {
    var x = "Hello";
    console.log(x); // Shows "Hello" to console
}());
 console.log(x); // Throws error "Uncaught ReferenceError: x is not defined"

It is also possible to pass arguments to IIFE. This is how we do that.

(function(firstName, lastName) {
    var fullName = firstName + " " + lastName;
    console.log(fullName);
}("Jim", "Cooper"));
// Output: Jim Cooper

The values “Jim” and “Cooper” are passed to function as firstName and lastName and are used to construct fullName.

Now that we understand IIFE, let’s take an example of a product details page in an e-commerce application and see how IIFE solves some serious problems.

You can just think of a global variable productName in an e-commerce application that was created in global scope in a JS file running on product details page. Product details page might be executing a whole lot of JavaScript code spread across multiple JS files. While script to load and display the product information might be written in one file, script to add product to the cart may exist in some other file. There could be a dedicated JS file to load and display the product reviews. The point here is, web pages in real world applications today runs a whole bunch of JavaScript files to handle different scenarios.

The product name is such a common term that more than one JS file on the product details page may have a variable named productName. If variables are not created with local scoping in place, then chances are high that the variable productName gets modified accidentally in some other file.

The real world applications are implemented with proper scoping in mind. I hope at this point you would agree that global variables are evil in JavaScript and creating global variables is a bad practice. Let’s see an example and try to understand the problem with the code.

function getPhone() {
   return "iPhone7";
}

function displayProductDetails(productName) {
   console.log("This is " + productName);
}

function addProductToCart(productName) {
   console.log(productName + " added to your shopping cart");
}

function makePayment(productName) {
   console.log("Making payment for " + productName);
}

function getRelatedProducts() {
   var relatedProducts = ["Headphone", "Phone cover", "Tempered glass"];
   return relatedProducts;
}

function suggestMeAHeadphone() {
   var relatedProducts = getRelatedProducts();
   productName = relatedProducts[0];
   return productName;
}

var productName = getPhone();
displayProductDetails(productName);
addProductToCart(productName);
var headPhone = suggestMeAHeadphone();
makePayment(productName);

// Output:
// This is iPhone7
// iPhone7 added to your shopping cart
// Making payment for Headphone

The example above demonstrates a product details page where product details are loaded and displayed in the user interface. User can add the product to the cart. User can optionally select a product from related products suggestion and may add to the cart (I haven’t written code for adding related product to the cart for the simplicity). Finally, user makes the payment for the product (Phone).

This is not an example you will appreciate a lot but the intention here is to understand the problems caused by global variables. If you see the code carefully, the call to function getPhone returns a product which is stored in a variable productName. Since the variable is outside of any function, it will exist in global namespace.

Now look at the call to suggestMeAHeadphone function that happens just before makePayment. suggestMeAHeadphone function makes a call to the function getRelatedProducts, assigns the first product from the list of related products to variable productName and returns the productName. You might have noticed that variable productName has been assigned a new value, the name of the headphone in the function suggestMeAHeadphone. Finally, the function makePayment will be called to finalize the checkout process. But, due to all the evilness of global variable productName, makePayment function will write the statement “Making payment for Headphone” while it is supposed to write “Making payment for iPhone7”.

Combat this with IIFE

Now since you know the basics of Immediately Invoked Function Expressions, let’s try to write our e-commerce example using IIFE and avoid the variables from being accessible to the code outside of the local scope. I will put all the code in an IIFE except the code for handling “Related products”. Have a look.

(function() {
    function getPhone() {
       return "iPhone7";
    }

    function displayProductDetails(productName) {
       onsole.log("This is " + productName);
    }

    function addProductToCart(productName) {
       console.log(productName + " added to your shopping cart");
    }

    function makePayment(productName) {
       console.log("Making payment for " + productName);
    }

    var productName = getPhone();
    displayProductDetails(productName);
    addProductToCart(productName);
    makePayment(productName);
}());

// Output: 
// This is iPhone7
// iPhone7 added to your shopping cart
// Making payment for iPhone7

I will again say that this code is not very realistic as many things like adding product to the cart and making payment will happen when user clicks on some button in user interface. I kept the example short and simple to focus on the core of our discussion.

I will put the remaining of the code dedicated to handle “Related products” in a different IIFE, which may exist in a different JS file altogether.

(function(){
    function getRelatedProducts() {
       var relatedProducts = ["Sony Headphone", "Phone cover", "Tempered glass"];
       return relatedProducts;
    }

    function suggestMeAHeadphone() {
       var relatedProducts = getRelatedProducts();
       var productName = relatedProducts[0];
       console.log("We suggest you to buy " + productName);
       return productName;
    }
    var headPhone = suggestMeAHeadphone();
}());

// Output: We suggest you to buy Sony Headphone

By achieving local scoping with IIFEs, our variable productName is safe now. Though I have used var keyword before productName in the second IIFE, missing out the var will create a new global variable productName and the same variable in first IIFE is still safe. If you just ignore the quality of the e-commerce example I have presented, you must be able to understand the IIFE by now and their use in avoiding global scope pollution. Most of the modern JavaScript libraries like jQuery, Backbone use IIFE pattern to keep all the code in local scope.

That’s it!

Hope you found the post useful. This was the first and introductory post on managing the scope in JavaScript. In the next post I will take you through the Module Pattern and Revealing Module Pattern to achieve the implementation of private variables and functions.

Do you have any questions or was there anything unclear? Do leave your comments and share the post with your buddies. How about ending this post with an IIFE leaving a message for you?

(function() {
    alert("Happy JavaScripting!!");
}());

You might also be interested in:

Share This:

7 Comments

  1. john

    Can you please explain why this happened?

    “But, due to all the evilness of global variable productName, makePayment function will write the statement “Making payment for Headphone” while it is supposed to write “Making payment for iPhone7”.”

    Why “Making payment for Headphone” would be printed, I don’t get?

  2. john

    I see now. Honestly at first glance I don’t seem to like your example – you seem to be misusing global variables. Are you sure you couldn’t use globals in your example, such that all would be ok? you could have declared productName local inside suggestMeHeadphone

    1. Hi, you are right when saying that I could have used a local variable productName inside suggestMeAHeadhone and all would be right. But there is another side of story where global variables do the damage and that is when by any chance you forget to declare a variable with var keyword. Read the para “The product name is such a common term that….” again. If you are sure enough to do a careful programming throughout your application then all is fine. I appreciate your comment though. Thanks.

  3. john

    there are two sides of story as I see. If I carefully program my app I may use globals safely within my app – but there is no guarantee I don’t clash with stuff from other files, and that’s where IIFE would be useful, that is how I got it.

Leave a Reply