Immediately Invoked Function Expressions (IIFEs)

Hero image for Immediately Invoked Function Expressions (IIFEs). Image by Scott Rodgerson.
Hero image for 'Immediately Invoked Function Expressions (IIFEs).' Image by Scott Rodgerson.

In JavaScript, functions are firstclass citizens, meaning that functions can be assigned to variables, passed as arguments to other functions, and returned as values from functions. Functions can also be declared and invoked at the same time, creating what is known as an Immediately Invoked Function Expression (IIFE).

IIFE is a useful design pattern for creating private scopes and avoiding variable collisions in JavaScript code. This pattern has become very popular in modern JavaScript development, particularly when working with modules. In this article, we will discuss the basics of IIFE, advanced code examples that can be used in realworld development, compare IIFE with other strategies, and cover potential issues that developers may come across whilst working with modules.


Basic Example of IIFE

Let's kick things off with a basic example of IIFE. The following code creates a basic function which takes two parameters and returns their sum:

(function (x, y) {  console.log(x + y);})(2, 3);  //=> 5

Here, the function is wrapped in parentheses and immediately invoked with two arguments: 2 and 3. The result is logged to the console.

The IIFE pattern can also be used to create a private scope for variables. Consider this example:

(function () {  const x = 1;  console.log(x);})();  //=> 1

In this example, the variable x is declared inside the IIFE and is not accessible outside the function. This creates a private scope for the variable.


Advanced Examples of IIFE

IIFE can be used in many advanced scenarios in realworld development. Here are some examples:

Example 1: Creating a Module

IIFE is often used to create a module in JavaScript. A module is a selfcontained block of code that can be easily reused and maintained. In this example, we will create a module that contains a function to calculate the area of a circle:

const circle = (function () {  const pi = 3.14;  function calculateArea(radius) {    return pi * radius * radius;  }  return {    calculateArea: calculateArea,  };})();console.log(circle.calculateArea(5));  //=> 78.5

Here, an IIFE is used to create a module called circle. The module contains a constant pi and a function calculateArea which takes the radius of a circle as input and returns its area. The calculateArea function is returned as a property of the module. The module can be accessed using the circle variable and the calculateArea function can be invoked using circle.calculateArea(5).

Example 2: Using Arrow Functions

Arrow functions were introduced in ECMAScript 6 and provide a more concise syntax for writing functions. Arrow functions can also be used inside IIFE to create more readable code. For example:

const sum = ((x, y) => {  console.log(x + y);})(2, 3);  //=> 5

In this example, an arrow function is used inside the IIFE to calculate the sum of two numbers. The arrow function takes two parameters (x and y) and returns their sum. The arrow function is immediately invoked with arguments 2 and 3.

Example 3: Using Destructuring

Destructuring is a feature introduced in ECMAScript 6 that allows us to extract values from objects and arrays. Destructuring can be used inside IIFE to make the code even more readable and concise. Here's an example:

const user = {  name: 'John Doe',  age: 30,  email: 'john.doe@example.com',};(function ({ name, age, email }) {  console.log(`${name} is ${age} years old and has an email ${email}.`);})(user);  //=> John Doe is 30 years old and has an email john.doe@example.com.

In this example, destructuring is used inside the IIFE to extract the name, age, and email properties from the user object.


Comparison with Other Strategies

IIFE is just one of the many strategies that can be used to create private scopes in JavaScript. Another strategy is to use the let and const keywords to declare variables inside a block. Consider the following:

{  const x = 1;  console.log(x);}  //=> 1

The variable x is declared inside a block and is not accessible outside the block. This creates a private scope for the variable.

Whilst the let and const keywords provide a simple way to create private scopes, they cannot be used to create a module with a public API. IIFE provides a way to create a module with a public API that can be easily reused and maintained.


Potential Issues

When using IIFE, developers may come across issues related to variable scoping and memory usage:

Variable Scoping

In some cases, variables declared inside an IIFE may unintentionally leak into the global scope, causing variable collisions. This can happen when a variable is not properly declared with the const or let keyword inside the IIFE.

Here's an example:

(function () {  var x = 1;  y = 2;  // This variable will leak into the global scope})();console.log(x);  //=> ReferenceError: x is not definedconsole.log(y);  //=> 2

As the variable y is not declared with const or let inside the IIFE, it is defined within (and attached to) the global scope. To avoid this issue, you should always use const or let when declaring variables inside an IIFE.

Memory Usage

Each IIFE call creates an execution context and local bindings, just as an ordinary function call does. Those bindings normally become unreachable when the call returns unless a closure or another reachable object retains them. Consider the following code snippet:

for (var i = 0; i < 1000000; i++) {  (function () {    var x = i;    // do some work with x  })();}

Admittedly it is an extreme example, but here the IIFE is called 1,000,000 times. Each call creates temporary bindings; this is execution and allocation work, not a leak, provided nothing reachable retains those bindings after the call returns.

Assigning a local primitive to null does not provide useful manual garbage collection. The local binding becomes unreachable when the call returns, so the equivalent example is:

for (var i = 0; i < 1000000; i++) {  (function () {    var x = i;    // do some work with x    // x becomes unreachable after this call returns  })();}

In an extension of this, developers should be mindful of the performance impact of using IIFEs excessively; whilst they can be a useful tool in certain situations (such as encapsulating code and preventing variable collisions), excessive use of IIFEs can lead to decreased performance due to the additional overhead of creating a new function scope for each call.

As with any programming tool, it's important to use IIFEs carefully and with consideration for their potential impact on performance and memory usage.


The Wrap‑Up

Invoked Function Expressions (IIFE) are a powerful tool in JavaScript for encapsulating code and preventing variable collisions. By defining and immediately invoking a function, developers can create a private scope where variables and functions are kept separate from the global scope.

However, as with any programming tool, there are potential issues to be aware of when using IIFEs. Variable scoping and memory usage can be a concern if not managed properly, and excessive use of IIFEs can lead to decreased performance due to the additional overhead of creating a new function scope for each call.

Despite these considerations, IIFEs remain useful when code needs a selfcontained scope. Use const and let to declare bindings correctly, and release any external references, listeners or closures that genuinely retain state; local bindings need no manual null assignment when the call returns.


Planning a platform change?

I help teams make difficult platform work clearer, from architecture decisions and migrations to launch recovery, performance, and search visibility.