JavaScript
Completed
-
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)
24: Loops: for, while, for...of, for...in
Early in my career, I treated the standard for loop like a Swiss Army knife. I used it for everything. If I had a list of data, I'd write for (let i = 0; i < items.length; i++). It works, sure, but it's noisy. When you spend eight hours a day reading code, seeing that same index boilerplate over and over becomes mental clutter. You're spending more time managing the counter i than you are actually thinking about the data.
The manual grind of the index
Let's say we're building a simple system to process a queue of user notifications. The "naive" way is to track the index manually. It looks like this:
const notifications = ['Welcome!', 'Your order shipped', 'Password changed', 'New login detected'];
for (let i = 0; i < notifications.length; i++) {
console.log(`Processing notification ${i + 1}: ${notifications[i]}`);
}
Now, this is fine if you specifically need the index number for some calculation. But notice how much "plumbing" is here. You're initializing a variable, defining a boundary condition, and incrementing a counter. If you accidentally type i <= notifications.length instead of <, you've just introduced an "off-by-one" error that will crash your app with an undefined value on the last iteration. I've wasted hours of my life debugging that exact typo.
Cleaning up the noise with for...of
If you just want the actual items in the array, stop managing the index. This is where for...of comes in. It's the modern way to say, "I don't care where the item is in the list; just give me the item."
for (const note of notifications) {
console.log(`Processing: ${note}`);
}
Compare that to the first example. The boilerplate is gone. There's no i to mess up, and the intent is crystal clear. I always tell my juniors: if you aren't using the index for logic, for...of is your default. It's cleaner, safer, and much faster to read during a code review.
The object trap and for...in
Now, things get tricky when we move from arrays to objects. You might be tempted to use for...of on an object, but you'll quickly find it throws a TypeError because objects aren't "iterable" in the same way arrays are. This is where for...in enters the picture.
Imagine we have a user's settings object. We want to print every setting and its value:
const settings = { theme: 'dark', notifications: true, language: 'en' };
for (const key in settings) {
console.log(`${key}: ${settings[key]}`);
}
Here is the warning I give everyone: do not use for...in for arrays. Because for...in iterates over all enumerable properties, it can sometimes pick up things you didn't expect (like custom properties added to the Array prototype by a library). Use for...in for objects, and for...of for arrays. Keep them strictly separated in your mind.
When you don't actually know the end date
Finally, there's the while loop. All the loops we've discussed so far assume we have a collection of a certain size. But in the real world, you often loop based on a condition, not a count.
Imagine you're polling an API to see if a background job is finished. You don't know if it will take 2 iterations or 200. Using a for loop here would be a guess. A while loop is the right tool for the job:
let isJobComplete = false;
let attempts = 0;
while (!isJobComplete && attempts < 10) {
isJobComplete = await checkJobStatus();
attempts++;
if (!isJobComplete) await sleep(1000);
}
The trade-off here is risk. A for loop has a built-in exit strategy (the length of the array). A while loop can easily become an infinite loop if your condition never becomes false. That's why I always include a "safety valve" (like attempts < 10) to make sure the browser doesn't freeze if the server never responds.
📋 Practical Task
Exercise: The VIP Guest List Filter
You have been given an array of guest objects for an exclusive event. Each object contains a name and a status (either 'standard' or 'VIP').
Your task is to write a script that does the following:
- Iterates through the
guestsarray. - Prints "Checking guest: [name]" for every person.
- If a guest with the status 'VIP' is found, print "VIP found: [name]! Stopping search." and immediately exit the loop using the
breakkeyword.
Starter Code:
const guests = [
{ name: 'Alice', status: 'standard' },
{ name: 'Bob', status: 'standard' },
{ name: 'Charlie', status: 'VIP' },
{ name: 'Diana', status: 'standard' },
];
// Your loop goes here
There are no comments for now.