- What IIFEs are and why they were invented
- How to create private variables and avoid global pollution
- What namespaces are and how to use them
- Modern ES6 modules: import, export, and organizing large projects
- The evolution from IIFEs to modules and why it matters
- Common mistakes with modules and how to avoid them
What is an IIFE?
An IIFE (Immediately Invoked Function Expression) is a JavaScript function that runs as soon as it’s defined. As documented on MDN, it creates a private scope to protect variables from polluting the global namespace. This pattern was essential before ES6 modules existed.() at the end immediately invokes it. This was the go-to pattern for creating private scope before JavaScript had built-in modules. According to the 2023 State of JS survey, ES modules are now used by the vast majority of JavaScript developers, but IIFEs remain common in bundler output and legacy codebases.
import/export), so you won’t write many IIFEs in modern code. However, understanding them is valuable. You’ll encounter IIFEs in older codebases, libraries, and they’re still useful for specific cases like async initialization or quick scripts.The Messy Desk Problem: A Real-World Analogy
Imagine you’re working at a desk covered with papers, pens, sticky notes, and coffee cups. Everything is mixed together. When you need to find something specific, you have to dig through the mess. And if someone else uses your desk? Chaos. Now imagine organizing that desk:- First, we had the messy desk — everything in the global scope
- Then, we invented IIFEs — a clever trick to create private spaces
- Next, we created Namespaces — grouping related things under one name
- Finally, we got Modules — the modern, built-in solution
Part 1: IIFE — The Self-Running Function
Breaking Down the Name
The acronym IIFE tells you exactly what it does:- Immediately — runs right now
- Invoked — called/executed
- Function Expression — a function written as an expression (not a declaration)
Expression vs Statement: Why It Matters for IIFEs
To understand IIFEs, you need to understand the difference between expressions and statements in JavaScript.The Anatomy of an IIFE
Let’s break down the syntax piece by piece:IIFE Variations
There are several ways to write an IIFE. They all do the same thing:Why Were IIFEs Invented?
Before ES6 modules, JavaScript had a big problem: everything was global. When scripts were loaded with regular<script> tags, variables declared with var outside of functions became global and were shared across all scripts on the page, leading to conflicts:
Practical Example: Creating Private Variables
One of the most powerful uses of IIFEs is creating private variables that can’t be accessed from outside:IIFE with Parameters
You can pass values into an IIFE:When to Use IIFEs Today
With ES6 modules, IIFEs are less common. But they’re still useful for:1. One-time initialization code
1. One-time initialization code
2. Creating async IIFEs
2. Creating async IIFEs
3. Avoiding global pollution in scripts
3. Avoiding global pollution in scripts
Part 2: Namespaces — Organizing Under One Name
What is a Namespace?
A namespace is a container that groups related code under a single name. It’s like putting all your kitchen items in a drawer labeled “Kitchen.”Why Use Namespaces?
Creating a Namespace
The simplest namespace is just an object:Nested Namespaces
For larger applications, you can nest namespaces:Combining Namespaces with IIFEs
The best of both worlds: organized AND private:Part 3: ES6 Modules — The Modern Solution
What are Modules?
Modules are JavaScript’s built-in way to organize code into separate files, each with its own scope. Unlike IIFEs and namespaces (which are patterns), modules are a language feature. Theexport statement makes functions, objects, or values available to other modules. The import statement brings them in.
Why Modules are Better
How to Use Modules
In the Browser
In Node.js
require() and module.exports? You might see this older syntax in Node.js code:import/export) are the modern standard and work in both browsers and Node.js. New projects should use ES modules.Exporting: Sharing Your Code
There are two types of exports: named exports and default exports.Named Exports
Named exports let you export multiple things from a module. Each has a name.Default Export
Each module can have ONE default export. It’s the “main” thing the module provides.When to Use Each
- Named Exports
- Default Export
- You’re exporting multiple things
- You want clear, explicit imports
- You want to enable tree-shaking
Importing: Using Other People’s Code
Named Imports
Import specific things by name (must match the export names):Default Import
Import the default export with any name you choose:Side-Effect Imports
Sometimes you just want to run a module’s code without importing anything:Import Syntax Summary
Organizing a Real Project
Let’s see how modules work in a realistic project structure:The Index.js Pattern (Barrel Files)
Useindex.js to re-export from multiple files:
Real Example: A Simple App
Dynamic Imports
Sometimes you don’t want to load a module until it’s needed. Dynamic imports load modules on demand:The Evolution: From IIFEs to Modules
Here’s how the same code would look in each era:- Era 1: Global (Bad)
- Era 2: IIFE (Better)
- Era 3: ES6 Modules (Best)
Common Patterns and Best Practices
1. One Thing Per Module
Each module should do one thing well:2. Keep Related Things Together
3. Avoid Circular Dependencies
4. Consider Default Exports for Components/Classes
A common convention is to use default exports when a module has one main purpose:5. Use Named Exports for Utilities
Common Mistakes to Avoid
Mistake 1: Confusing Named and Default Exports
One of the most common sources of confusion is mixing up how to import named vs default exports:Mistake 2: Circular Dependencies
Circular dependencies occur when two modules import from each other. This creates a “chicken and egg” problem that causes subtle, hard-to-debug issues:Key Takeaways
- IIFEs create private scope by running immediately — useful for initialization and avoiding globals
- Namespaces group related code under one object — reduces global pollution but isn’t true encapsulation
- ES6 Modules are the modern solution — file-based, true privacy, and built into the language
- Named exports let you export multiple things — import what you need by name
- Default exports are for the main thing a module provides — one per file
- Dynamic imports load modules on demand — great for performance optimization
- Each module has its own scope — variables are private unless exported
- Use modules for new projects — IIFEs and namespaces are for legacy code or special cases
- Organize by feature or type — group related modules in folders with index.js barrel files
- Avoid circular dependencies — they cause confusing bugs and loading issues
Test Your Knowledge
Try to answer each question before revealing the solution:Question 1: What does IIFE stand for and why was it invented?
Question 1: What does IIFE stand for and why was it invented?
Question 2: What's the difference between named exports and default exports?
Question 2: What's the difference between named exports and default exports?
- Can have multiple per module
- Must be imported by exact name (or aliased)
- Use
export { name }orexport function name() - Import with
import { name } from './module.js'
- Only one per module
- Can be imported with any name
- Use
export default - Import with
import anyName from './module.js'
Question 3: How do you create a private variable in an IIFE?
Question 3: How do you create a private variable in an IIFE?
Question 4: What's the difference between static and dynamic imports?
Question 4: What's the difference between static and dynamic imports?
- Loaded at the top of the file
- Always loaded, even if not used
- Analyzed at build time
- Syntax:
import { x } from './module.js'
- Can be loaded anywhere in the code
- Loaded only when the import() call runs
- Loaded at runtime, returns a Promise
- Syntax:
const module = await import('./module.js')
Question 5: Why should you avoid circular dependencies?
Question 5: Why should you avoid circular dependencies?
- Loading issues: When A loads, it needs B. But B needs A, which isn’t fully loaded yet.
- Undefined values: You might get
undefinedfor imports that should have values. - Confusing bugs: Hard to track down because the error isn’t where the bug is.
Question 6: When would you still use an IIFE today?
Question 6: When would you still use an IIFE today?
- Async initialization:
- One-time calculations:
-
Scripts without modules: When you’re adding a
<script>tag withouttype="module", IIFEs prevent polluting globals. - Creating private scope in non-module code.
Frequently Asked Questions
What is an IIFE in JavaScript?
What is an IIFE in JavaScript?
().Why were IIFEs used before ES6 modules?
Why were IIFEs used before ES6 modules?
What is the difference between IIFEs and ES6 modules?
What is the difference between IIFEs and ES6 modules?
What is a namespace in JavaScript?
What is a namespace in JavaScript?
var MyApp = MyApp || {} to organize code. The namespace pattern reduced global pollution but did not provide true privacy, which is why the module pattern and later ES6 modules became preferred.Are IIFEs still useful in modern JavaScript?
Are IIFEs still useful in modern JavaScript?
(async () => { ... })()), one-time configuration, and scripts loaded without type="module". They also appear frequently in build tool output and legacy codebases, so understanding them remains important for professional JavaScript development.Related Concepts
Scope and Closures
Higher-Order Functions
Design Patterns
Call Stack
Reference
IIFE — MDN
JavaScript Modules — MDN
Expression Statement — MDN
Namespace — MDN
Articles
Mastering Immediately-Invoked Function Expressions
JavaScript Modules: A Beginner's Guide
A 10 minute primer to JavaScript modules
ES6 Modules in Depth
JavaScript modules — V8
Modules — javascript.info
All you need to know about Expressions, Statements and Expression Statements
function(){}() fails but (function(){})() works. The expression vs statement distinction finally makes sense after reading this.