IIFE (Immediately Invoked Function Expression): A Complete Guide
Define and execute JavaScript functions immediately
What is an IIFE?
An IIFE (Immediately Invoked Function Expression) is a JavaScript function that is defined and executed immediately. It's a common design pattern that creates a private scope for your code, preventing variable pollution and naming conflicts in the global scope.
Basic Syntax
// Arrow function IIFE
(() => {
// Your code here
})();
// Traditional function IIFE
(function() {
// Your code here
})();
Why Use IIFEs?
1. **Scope Isolation**
IIFEs create a private scope, preventing variables from leaking into the global namespace:
// Without IIFE - pollutes global scope
var username = 'john_doe';
var password = 'secret123';
// With IIFE - contained scope
(() => {
var username = 'john_doe';
var password = 'secret123';
// These variables don't exist outside this function
})();
2. **Avoiding Naming Conflicts**
Perfect for preventing variable name collisions:
// Problem: Multiple scripts using same variable names
var config = { theme: 'dark' }; // Script 1
var config = { api: 'v1' }; // Script 2 - overwrites Script 1!
// Solution: Each script uses IIFE
(() => {
var config = { theme: 'dark' }; // Script 1 - isolated
})();
(() => {
var config = { api: 'v1' }; // Script 2 - isolated
})();
3. **Module Pattern**
IIFEs are the foundation of the module pattern:
const myModule = (() => {
// Private variables
let privateCounter = 0;
// Private function
function privateIncrement() {
privateCounter++;
}
// Public API
return {
increment: privateIncrement,
getCount: () => privateCounter,
reset: () => privateCounter = 0
};
})();
myModule.increment();
console.log(myModule.getCount()); // 1
// privateCounter is not accessible from outside
Real-World Examples
Example 1: Configuration Setup
const appConfig = (() => {
const isDevelopment = process.env.NODE_ENV === 'development';
const apiUrl = isDevelopment ? 'http://localhost:3000' : 'https://api.example.com';
return {
apiUrl,
isDevelopment,
timeout: 5000
};
})();
Example 2: Event Listener Setup
(() => {
const button = document.getElementById('myButton');
let clickCount = 0;
button.addEventListener('click', () => {
clickCount++;
console.log(`Button clicked ${clickCount} times`);
});
})();
Example 3: Library Initialization
(() => {
// Check if library already exists
if (window.MyLibrary) {
console.warn('MyLibrary already loaded');
return;
}
// Initialize library
window.MyLibrary = {
version: '1.0.0',
init: function() {
console.log('Library initialized');
}
};
})();
IIFE Variations
1. **With Parameters**
((name, age) => {
console.log(`Hello ${name}, you are ${age} years old`);
})('Alice', 25);
2. **Returning Values**
const result = (() => {
const a = 10;
const b = 20;
return a + b;
})();
console.log(result); // 30
3. **Async IIFE**
(async () => {
try {
const data = await fetch('/api/data');
const json = await data.json();
console.log(json);
} catch (error) {
console.error('Error:', error);
}
})();
4. **Conditional IIFE**
const utils = typeof window !== 'undefined' ? (() => {
// Browser environment
return {
storage: localStorage,
navigate: (url) => window.location.href = url
};
})() : (() => {
// Node.js environment
return {
storage: require('fs'),
navigate: () => console.log('Navigation not available in Node.js')
};
})();
Electron/executeJavaScript Use Case
In our Streamer Helper project, we used IIFE to solve a variable naming conflict:
// Problem: This would conflict with existing global variables
const twitchCredentials = await mainWindow.webContents.executeJavaScript(`
const username = localStorage.getItem('twitch_username'); // ❌ Conflicts!
const oauth = localStorage.getItem('twitch_oauth');
// ... more code
`);
// Solution: IIFE creates isolated scope
const twitchCredentials = await mainWindow.webContents.executeJavaScript(`
(() => {
const autoConnectUsername = localStorage.getItem('twitch_username'); // ✅ Safe!
const autoConnectOauth = localStorage.getItem('twitch_oauth');
return {
username: autoConnectUsername,
oauth: autoConnectOauth
};
})()
`);
Best Practices
✅ **Do:**
- Use IIFEs to avoid global namespace pollution
- Use IIFEs for one-time initialization code
- Use IIFEs to create private scopes in older JavaScript environments
- Use descriptive variable names even within IIFEs
❌ **Don't:**
- Overuse IIFEs in modern ES6+ code (use modules instead)
- Create overly complex IIFEs that are hard to read
- Use IIFEs when a simple function call would suffice
Modern Alternatives
In modern JavaScript, you might use:
ES6 Modules
// utils.js
const privateVar = 'secret';
export function publicFunction() {
return privateVar.toUpperCase();
}
// main.js
import { publicFunction } from './utils.js';
Block Scope with let/const
{
const scopedVariable = 'only available in this block';
console.log(scopedVariable);
}
// scopedVariable is not accessible here
Browser Compatibility
IIFEs work in all JavaScript environments:
- ✅ All modern browsers
- ✅ Internet Explorer (all versions)
- ✅ Node.js
- ✅ Electron applications
Conclusion
IIFEs are a powerful pattern for creating isolated scopes and avoiding naming conflicts. While modern JavaScript provides alternatives like modules and block scope, IIFEs remain useful for:
- Legacy code maintenance
- Script injection scenarios
- One-time initialization
- Creating private scopes in any JavaScript environment
Understanding IIFEs helps you write cleaner, more maintainable JavaScript code and avoid common pitfalls like global namespace pollution and variable conflicts.
This guide was created as part of the Streamer Helper project development, where IIFEs helped solve real-world variable scoping issues in Electron applications.
Recommended Articles

Building Modern Web Applications
Discover how modern web development has transformed in 2025. Learn the essential tools, frameworks, and practices that make building web applications faster, smarter, and more powerful than ever before.

PowerShell Commands for Checking Windows Executable Properties
No excerpt available