Marius Schulz
Marius Schulz
Front End Engineer

Disassembling JavaScript's IIFE Syntax

If you've spent even just a little time in the JavaScript world, you've likely come across the following pattern quite frequently. It's called an IIFE, which stands for immediately invoked function expression:

(function () {
  // ...
})();

A lot of the time, the function scope of an IIFE is used to prevent leaking local variables to the global scope. Similarly, IIFEs can be used to wrap state (or data in general) that's meant to be private. The basic pattern is the same in both cases. For more IIFE use cases, check out this excellent post by @toddmotto.

However, you might've been wondering why we write IIFEs the way we do. They look a little odd, after all. Let's inspect the IIFE syntax and disassemble it into its parts.

#The IIFE Syntax

At the heart of each IIFE is the function itself. It spans from the function keyword to the closing brace:

function() {
  // ...
}

This piece of code alone is not valid JavaScript, though. When the parser sees the function keyword at the beginning of the statement, it expects a function declaration to follow. Since the function doesn't have a name, it doesn't follow the grammar rules of a function declaration. Therefore, the parsing attempt fails and we get a syntax error.

We somehow have to make the JavaScript engine parse a function expression rather than a function declaration. If you're unsure about the difference, please refer to my post on the different kinds of function definitions in JavaScript.

The trick is quite simple, actually. We can fix the syntax error by wrapping the function within parentheses, which results in the following code:

(function () {
  // ...
});

Once the parser encounters the opening parenthesis, it expects an expression, followed by a closing parenthesis. Contrary to function declarations, function expressions don't have to be named, so the above (parenthesized) function expression is a valid piece of JavaScript code.

Take a look at the ParenthesizedExpression production in section 12.2 of the ECMAScript specification if you want to learn more about parenthesized expressions in JavaScript.

The only part that's left now is to invoke the function expression we've just created. Right now, the function never executes because it's never called, and without being assigned to anything, there's no way of getting hold of it later. We'll add a pair of parentheses (and a semicolon, for good measure) at the end:

(function () {
  // ...
})();

And here we go — that's the IIFE we've been looking for. If you think about the name for a second, it perfectly describes what we've put together: an immediately invoked function expression.

The remainder of this post gives an overview over some variations of the IIFE syntax that exist for different reasons.

#Where do the parentheses go?

So far, we've been placing the parentheses that invoke the function right after the closing wrapper parenthesis:

(function () {
  // ...
})();

However, some people like Douglas Crockford famously don't like the aesthetics of a dangling pair of parentheses, so they place them within the wrapper:

(function () {
  // ...
}());

Both approaches are perfectly fine (and semantically equivalent) implementations of an immediately invoked function expression, so just pick the one you find more appealing.

#Named IIFEs

The function that's being wrapped is a regular function expression, which means you can give it a name and turn it into a named function expression, if you like:

(function iife() {
  // ...
})();

Note that you still cannot leave out the wrapping parentheses around the function. This piece of code is still not valid JavaScript:

function iife() {
    // ...
}();

The parser can now successfully parse a function declaration. Immediately after it, though, it unexpectedly encounters the ( token and throws a syntax error. That's because unlike function expressions, function declarations cannot be immediately invoked.

#Preventing Issues when Concatenating Files

Sometimes, you might encounter an IIFE that has a leading semicolon in front of the opening wrapping parenthesis:

(function () {
  // ...
})();

This defensive semicolon exists to prevent issues that might arise when concatenating together two JavaScript files. Imagine the first file contains the following code:

var foo = bar;

Note there's no semicolon terminating the variable declaration statement. If the second JavaScript file contained an IIFE without a leading semicolon, the concatenated result would be as follows:

var foo = bar(function () {
  // ...
})();

This might look like an assignment of the identifier bar to the variable foo followed by an IIFE, but it's not. Instead, bar is attempted to be invoked as a function that gets passed another function as an argument. Removing the line break after bar should make the code clearer:

var foo = bar(function () {
  // ...
})();

The leading semicolon prevents this unwanted function invocation:

var foo = bar;
(function () {
  // ...
})();

Even if the leading semicolon is not preceded by any other code, it is a grammatically correct language construct. In that case, it would be parsed as an empty statement, which simply doesn't do anything and therefore does no harm.

The rules for JavaScript's automatic semicolon insertion are tricky and easily lead to unexpected errors. I recommend you always explicitly write out semicolons instead of having them inserted automatically.

#Arrow Functions Instead of Function Expressions

With ECMAScript 2015, JavaScript was extended by the arrow function syntax for function definitions. Just like function expressions, arrow functions are expressions, not statements. This means that we could create an immediately invoked arrow function if we wanted to:

(() => {
  // ...
})();

Note that the wrapping parentheses around the arrow function are required for the immediate invocation to work. If you leave them out, the JavaScript parser will complain about the unexpected token ( after the closing brace. That said, I wouldn't recommend you write your IIFEs using arrow functions in the first place — I find the classic version using the function keyword much easier to read.