-
Section 1: Getting Started
-
Section 2: Core Syntax and Types
-
Section 3: Strings and Numbers in Depth
-
Section 4: Control Flow
-
Section 5: Functions
-
Section 6: Objects and Arrays
-
Section 7: Maps, Sets, and Symbols
-
Section 8: Asynchronous JavaScript
-
Section 9: Object-Oriented and Prototypes
-
Section 10: The DOM
-
Section 11: Browser APIs
-
Section 12: Modern JavaScript (ES2015-ES2025)
-
Section 13: Functional Programming Patterns
-
Section 14: Error Handling and Debugging
-
Section 15: Testing
-
Section 16: Accessibility for JavaScript Developers
-
Section 17: Internationalization and Localization
-
Section 18: Performance
-
Section 19: Node.js Fundamentals
-
Section 20: Regular Expressions
-
Section 21: Design Patterns in JavaScript
-
Section 22: Security Basics
-
Section 23: Data Structures and Algorithms in JavaScript
-
Section 24: Practical Projects
-
Section 25: More Advanced Async Patterns
-
Section 26: More Object and Class Practice
-
Section 27: Working with Dates and Internationalization
-
Section 28: Web Components
-
Section 29: More DOM and Browser Practice
-
Section 30: Build Tooling for Vanilla JavaScript
-
Section 31: More Practice Projects
-
Section 32: Interview and Algorithm Practice
-
Section 33: Error Objects (MDN Reference)
-
Section 34: TypedArrays and Binary Data
-
Section 35: Reflection and Metaprogramming (MDN Reference)
-
Section 36: More Global Functions (MDN Reference)
34: Immediately Invoked Function Expressions
Imagine you need to do a quick home repair—say, fixing a leaky faucet. You don't want to buy a massive, permanent workbench and leave it in the middle of your kitchen for the rest of your life. Instead, you bring in a small, portable tool kit, do the job, and then pack everything back up and put the kit away. The kitchen stays clean, and the only thing that remains is the fixed faucet.
An Immediately Invoked Function Expression, or IIFE, is exactly that portable tool kit for your code. It allows you to create a temporary "bubble" where you can do some work, declare some variables, and execute logic, and then immediately vanish. Once the IIFE finishes running, everything inside that bubble—except for whatever you explicitly decided to export—is gone. It doesn't clutter up your global namespace.
Wrapping the logic to protect the global scope
In the old days of JavaScript (and still in many legacy codebases), we didn't have modules. If you declared a variable at the top of your script, it was global. If you were using three different libraries and two of them both decided to use a variable named config, they would overwrite each other, and your app would crash in a way that was a nightmare to debug.
To stop this, I often use an IIFE. Here is a real example: let's say we want to initialize a user's theme preference from local storage, but we don't want the helper variables we use during that process to be accessible to the rest of the application.
(function() {
const themeKey = 'app_user_theme';
const savedTheme = localStorage.getItem(themeKey);
if (savedTheme) {
document.body.className = savedTheme;
} else {
document.body.className = 'theme-light';
}
console.log('Theme initialized successfully.');
})();
Notice that themeKey and savedTheme only exist for the few milliseconds it takes for that function to run. If you try to console.log(themeKey) outside of that block, you'll get a ReferenceError. That's the goal. I've protected my "internal" variables from the rest of the world.
The magic of the double parentheses
You're probably wondering why the syntax looks so weird. Why the wrapping parentheses and the trailing ones? If I just wrote function() { ... }, JavaScript would think I'm trying to declare a named function and would throw a syntax error because I didn't give it a name.
- The first set of parentheses: These wrap the function and tell JavaScript, "Don't treat this as a declaration; treat it as a function expression." It essentially turns the function into a value.
- The second set of parentheses: These are the actual "call" operators. Since the first set of parentheses gave us a function value, the second set immediately executes that value.
It's a bit of a syntactic trick, but it's incredibly powerful for keeping your codebase lean.
Passing data into the bubble
Sometimes, you want your IIFE to use a global variable, but you want to "lock it in" locally for a slight performance boost or to make the code more readable. You can pass arguments into an IIFE just like a normal function.
const globalApiUrl = 'https://api.example.com/v1';
(function(apiUrl) {
// Inside here, we use 'apiUrl' instead of the global variable
console.log('Connecting to ' + apiUrl + '...');
// Setup logic here...
})(globalApiUrl);
I personally find this useful when I'm writing a script that needs to be bundled with others. By passing the global in as an argument, it becomes very clear to anyone reading the code exactly which external dependencies the IIFE relies on.
📋 Practical Task
Build a Private Page-View Counter
Your task is to create a page-view counter that keeps track of how many times a "Like" button has been clicked. However, for security and stability reasons, the actual count variable must be private—it should be impossible to change the count by typing a variable name into the browser console.
Requirements:
- Use an IIFE to encapsulate the logic.
- Inside the IIFE, create a private variable
countinitialized to 0. - Inside the IIFE, create a function that increments the count and updates the text of an HTML element with the ID
counter-display. - Attach an event listener to a button with the ID
like-btnthat triggers the increment function. - Ensure that the
countvariable is not accessible in the global scope.
Starter HTML:
<button id="like-btn">Like</button>
<span id="counter-display">0</span>There are no comments for now.