Problem Statement
What is an IIFE? Explain the module pattern and how IIFE enables data privacy.
Explanation
IIFE stands for Immediately Invoked Function Expression. It is a function that executes immediately after being defined.
IIFE syntax:
Wrap function in parentheses to make it an expression. Add parentheses at the end to invoke it. Can use regular or arrow functions. Can pass arguments to the IIFE.
Purpose of IIFE:
Creates a new scope to avoid polluting global scope. Enables data privacy through closures. Provides encapsulation for variables and functions. Executes initialization code once.
Data privacy with IIFE:
Variables inside IIFE are not accessible from outside. Only returned values or objects are exposed. Creates private variables and public API. This is the basis of the module pattern.
Module pattern:
Uses IIFE to create a module with private and public members. Returns an object with public methods. Private variables are accessible only through returned methods. Provides encapsulation and information hiding.
Benefits:
Prevents global namespace pollution. Creates truly private data. Organizes code into reusable modules. Avoids variable collisions. Enables singleton pattern.
Modern alternatives:
ES6 modules with import and export. Block scope with let and const. Classes with private fields using hash.
When to use IIFE today:
Legacy code maintenance. When ES6 modules are not available. Quick scripts that need isolation. Library development for backward compatibility.
IIFE and module pattern were fundamental before ES6 modules and still appear in interviews and legacy code.
Code Solution
SolutionRead Only
// BASIC IIFE SYNTAX
// Function declaration (not IIFE)
function test() {
console.log('Not immediately invoked');
}
// IIFE - executes immediately
(function() {
console.log('Immediately invoked!');
})();
// Arrow function IIFE
(() => {
console.log('Arrow IIFE');
})();
// Alternative syntax (both work)
(function() {
console.log('Style 1');
}());
// IIFE with parameters
(function(name, age) {
console.log(name + ' is ' + age);
})('John', 30);
// IIFE returning a value
const result = (function() {
return 2 + 2;
})();
console.log(result); // 4
// DATA PRIVACY WITH IIFE
const counter = (function() {
// Private variable
let count = 0;
// Private function
function validateIncrement(value) {
return value > 0;
}
// Public API
return {
increment: function(value = 1) {
if (validateIncrement(value)) {
count += value;
}
return count;
},
decrement: function() {
count--;
return count;
},
getCount: function() {
return count;
},
reset: function() {
count = 0;
}
};
})();
console.log(counter.increment()); // 1
console.log(counter.increment(5)); // 6
console.log(counter.getCount()); // 6
// console.log(counter.count); // undefined (private!)
// counter.validateIncrement(); // Error (private!)
// MODULE PATTERN
const calculator = (function() {
// Private state
let history = [];
// Private helper
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]; // Return copy
},
clearHistory: function() {
history = [];
}
};
})();
console.log(calculator.add(5, 3)); // 8
console.log(calculator.subtract(10, 4)); // 6
console.log(calculator.getHistory());
// ['5 + 3 = 8', '10 - 4 = 6']
// REVEALING MODULE PATTERN
const userModule = (function() {
// Private
let users = [];
function validateUser(user) {
return user.name && user.email;
}
function addUser(user) {
if (validateUser(user)) {
users.push(user);
return true;
}
return false;
}
function getUsers() {
return users;
}
function removeUser(email) {
users = users.filter(u => u.email !== email);
}
// Reveal public methods
return {
add: addUser,
getAll: getUsers,
remove: removeUser
};
})();
userModule.add({ name: 'John', email: 'john@example.com' });
console.log(userModule.getAll());
// SINGLETON PATTERN WITH IIFE
const database = (function() {
let instance;
function createInstance() {
return {
connect: function() {
console.log('Connected to database');
},
query: function(sql) {
console.log('Executing:', sql);
}
};
}
return {
getInstance: function() {
if (!instance) {
instance = createInstance();
}
return instance;
}
};
})();
const db1 = database.getInstance();
const db2 = database.getInstance();
console.log(db1 === db2); // true (same instance)
// AVOIDING GLOBAL POLLUTION
// Bad - pollutes global scope
var temp = 'global';
var helper = function() {};
// Good - isolated in IIFE
(function() {
var temp = 'isolated';
var helper = function() {};
// Do work
})();
// console.log(temp); // 'global' (not affected)
// console.log(helper); // Still accessible
// MODERN ALTERNATIVES
// ES6 Modules
// export const myModule = { ... };
// import { myModule } from './module.js';
// Block scope
{
const privateVar = 'isolated';
// Use privateVar
}
// console.log(privateVar); // ReferenceError
// Class with private fields (ES2022)
class MyClass {
#privateField = 'private';
getPrivate() {
return this.#privateField;
}
}