IIFE
Run Once, Vanish Forever
LinkedIn Hook
(function() { ... })()— two extra parentheses and suddenly your function runs the moment it's defined and its internal scope disappears.That's an IIFE. "Immediately Invoked Function Expression." Pronounced "iffy."
Before ES6 gave us modules and
let/const, IIFEs were how JavaScript developers faked modules, hid private state, and avoided polluting the global namespace. They're the reason jQuery plugins all look the same. They're how the classicfor (var i...) setTimeout(...)bug got fixed.Even today, IIFEs are still the cleanest way to run initialization code inline, wrap third-party scripts, and create one-time-use scopes in non-module contexts.
In this lesson you'll see the IIFE syntax, the reason for the outer parentheses, and four real-world patterns: namespace protection, the module pattern, config initialization, and loop variable capture.
Read the full lesson -> [link]
#JavaScript #InterviewPrep #IIFE #ModulePattern #Closures #Scope #CodingInterview
What You'll Learn
- What an IIFE is and why those outer parentheses exist
- How IIFEs created "modules" before ES6 modules existed
- Four real-world IIFE patterns including the classic loop-variable fix
The Self-Destructing Message
An IIFE (pronounced "iffy") is a function that runs the moment it's defined. No separate call needed.
Think of an IIFE like a self-destructing message. It runs once, does its job, and its internal scope vanishes from the outside world. It's a one-time-use container.
Basic Syntax
// Anonymous IIFE
(function() {
console.log("I run immediately!");
})();
// "I run immediately!"
// Arrow function IIFE
(() => {
console.log("Arrow IIFE!");
})();
// Named IIFE — the name is only accessible inside the function
(function setup() {
console.log("Named IIFE: " + setup.name);
})();
// "Named IIFE: setup"
// setup is NOT accessible here
// console.log(setup); // ReferenceError
IIFE with Parameters and Return Values
// Passing arguments to IIFE
const result = (function(a, b) {
return a + b;
})(10, 20);
console.log(result); // 30
// IIFE with configuration
const config = (function() {
const env = "production";
const version = "2.1.0";
const debug = env !== "production";
return {
env,
version,
debug,
apiUrl: debug ? "http://localhost:3000" : "https://api.example.com"
};
})();
console.log(config.env); // "production"
console.log(config.apiUrl); // "https://api.example.com"
// 'env', 'version', 'debug' variables are private — not accessible outside
Use Case: Avoiding Global Pollution
// Without IIFE — pollutes global scope
var counter = 0;
var name = "App";
// These are now global variables anyone can overwrite
// With IIFE — everything stays private
(function() {
var counter = 0;
var name = "App";
// These are scoped to the IIFE, invisible to the outside
console.log(name + ": " + counter);
})();
// "App: 0"
// console.log(counter); // ReferenceError (if no global 'counter')
Use Case: Module Pattern (Pre-ES6)
const CounterModule = (function() {
// Private state
let count = 0;
// Private function
function log(msg) {
console.log("[Counter] " + msg);
}
// Public API (revealing module pattern)
return {
increment: function() {
count++;
log("Incremented to " + count);
},
decrement: function() {
count--;
log("Decremented to " + count);
},
getCount: function() {
return count;
}
};
})();
CounterModule.increment(); // [Counter] Incremented to 1
CounterModule.increment(); // [Counter] Incremented to 2
CounterModule.decrement(); // [Counter] Decremented to 1
console.log(CounterModule.getCount()); // 1
// CounterModule.count -> undefined (private!)
// CounterModule.log -> undefined (private!)
Use Case: Loop Variable Capture (Classic Problem)
// The classic bug with var in loops
for (var i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i); // 3, 3, 3 — all reference the same 'i'
}, 100);
}
// Fix with IIFE — creates a new scope for each iteration
for (var i = 0; i < 3; i++) {
(function(capturedI) {
setTimeout(function() {
console.log(capturedI); // 0, 1, 2
}, 100);
})(i);
}
// Modern fix: just use let
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100); // 0, 1, 2
}
Common Mistakes
- Forgetting the outer parentheses —
function() { ... }()is a syntax error at statement position because JS parses it as a function declaration. Wrapping in()forces it to be parsed as an expression. - Leaving off the trailing
()— without it, you've defined a function expression but never invoked it. No code runs. - Using IIFEs in modern ES modules where they aren't needed — module files already have their own scope. IIFEs are mostly for non-module scripts or for wrapping third-party code.
Interview Questions
Q: What is an IIFE and why would you use it?
An IIFE (Immediately Invoked Function Expression) is a function that executes immediately after it's defined. It's used to: (1) create private scope and avoid polluting the global namespace, (2) implement the module pattern (pre-ES6), (3) capture loop variables with
var, and (4) run initialization code once.
Q: What is the difference between named and anonymous IIFE?
A named IIFE (
(function mySetup() { ... })()) has a name accessible only inside the function itself (useful for recursion or debugging stack traces). An anonymous IIFE ((function() { ... })()) has no internal name. Both work identically — the name does not leak into the enclosing scope.
Q: Are IIFEs still relevant with ES6 modules and let/const?
Less so, but they still have uses: initializing complex config objects inline, creating private scope in scripts (non-modules), and wrapping third-party code. ES6 modules and block scoping (
let/const) have replaced most IIFE use cases.
Q: Can an IIFE take parameters? Can it return values?
Yes to both. You pass arguments in the final invocation parentheses:
(function(a, b) { return a + b; })(10, 20)returns30. The returned value can be assigned to a variable, which is how the module pattern exposes a public API.
Q: Why were IIFEs important before ES6? How does the module pattern use them?
Pre-ES6, JavaScript had no module system and no block scoping (
let/constdidn't exist). IIFEs were the only way to create private scope. The module pattern wraps state and helpers inside an IIFE and returns an object containing only the methods you want to expose — everything else stays private via closure.
Quick Reference — Cheat Sheet
IIFE — QUICK MAP
Syntax variants:
(function() { ... })() // anonymous, classic
(function name() { ... })() // named (useful for recursion/stack traces)
(() => { ... })() // arrow form
Why the outer parens?
Forces the function to be parsed as an EXPRESSION,
not a declaration. Without them -> SyntaxError.
Common uses:
1. Scope isolation -> keep vars out of global
2. Module pattern -> return public API, hide private state
3. Loop var capture -> pre-ES6 fix for `var` in setTimeout
4. One-shot init -> build a config inline
With parameters:
(function(a, b) { return a + b; })(10, 20) // 30
Modern replacement:
ES6 modules + let/const cover most IIFE cases.
Previous: Higher-Order Functions Next: Pure Functions & Side Effects -> The Vending Machine Rule
This is Lesson 6.3 of the JavaScript Interview Prep Course — 14 chapters, 87 lessons.