JavaScript IIFE (Immediately Invoked Function Expression)
An IIFE is a function that runs as soon as it is defined. It is a design pattern that creates a private scope, avoiding pollution of the global namespace. IIFEs were essential before ES6 modules and block-scoped variables.
IIFE Syntax
An IIFE is created by wrapping a function expression in parentheses and then immediately invoking it with another pair of parentheses.
// Standard IIFE syntax
(function() {
const message = 'Hello from IIFE!';
console.log(message);
})();
// Alternative syntax (parentheses placement)
(function() {
console.log('Alternative syntax');
}());
// IIFE with parameters
(function(name, age) {
console.log(name + ' is ' + age + ' years old');
})('Alice', 30);Syntax Variations
There are several valid syntax variations for IIFEs. All achieve the same result: immediately executing a function expression.
// Using void
void function() {
console.log('void IIFE');
}();
// Using unary operators
+function() {
console.log('+ IIFE');
}();
!function() {
console.log('! IIFE');
}();
// Named IIFE (name only accessible inside)
(function myIIFE() {
console.log('Named IIFE');
})();
// IIFE with return value
const result = (function() {
return 42;
})();
console.log('Result: ' + result);Avoiding Global Scope Pollution
The primary purpose of IIFEs is to create a private scope. Variables declared inside an IIFE are not accessible from outside, preventing conflicts with other scripts.
// Without IIFE: variables pollute global scope
// var counter = 0; // Global!
// var helper = function() {}; // Global!
// With IIFE: variables stay private
const app = (function() {
let counter = 0; // Private
const secret = 'hidden'; // Private
function increment() {
counter++;
return counter;
}
// Only expose what you want
return {
next: increment
};
})();
console.log(app.next());
console.log(app.next());
console.log(app.next());
console.log(typeof counter); // undefined (private!)The Module Pattern
The module pattern uses an IIFE to create a module with private variables and public methods. This was the standard pattern for creating modules before ES6.
const Calculator = (function() {
// Private state
let history = [];
// Private function
function addToHistory(operation) {
history.push(operation);
}
// Public API
return {
add: function(a, b) {
const result = a + b;
addToHistory(a + ' + ' + b + ' = ' + result);
return result;
},
subtract: function(a, b) {
const result = a - b;
addToHistory(a + ' - ' + b + ' = ' + result);
return result;
},
getHistory: function() {
return history.slice();
}
};
})();
console.log(Calculator.add(5, 3));
console.log(Calculator.subtract(10, 4));
console.log('History: ' + Calculator.getHistory());Async IIFE and Arrow IIFE
IIFEs can also be async (for top-level await patterns) or use arrow function syntax for shorter code.
// Arrow function IIFE
const greeting = (() => {
const name = 'World';
return 'Hello, ' + name + '!';
})();
console.log(greeting);
// Arrow IIFE with parameter
((name) => {
console.log('Arrow IIFE: Hi, ' + name);
})('Alice');
// Async IIFE (useful for top-level await in scripts)
(async function() {
// Can use await here
const data = await Promise.resolve('async data');
console.log('Async IIFE: ' + data);
})();
// Async arrow IIFE
(async () => {
const result = await Promise.resolve(42);
console.log('Async arrow IIFE: ' + result);
})();| IIFE Use Case | Modern Alternative |
|---|---|
| Private scope | ES6 block scope (let/const) |
| Module pattern | ES6 modules (import/export) |
| Avoid global pollution | ES6 modules (module scope) |
| Top-level await | Top-level await in modules |
| Configuration objects | Still useful |
| One-time initialization | Still useful |