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)
113: Declarative vs Imperative Style
I see this all the time in code reviews: a junior developer replaces a for loop with a .filter() or a .map() and tells me they've "switched to a declarative style." They think that "declarative" is just a fancy word for using built-in array methods. It's a common trap, but it's fundamentally wrong.
"Declarative is just using .map() and .filter()"
If you think declarative programming is just a specific set of syntax shortcuts, you're missing the mental shift. Using a method like .filter() is an example of declarative code, but the style itself is about the intent of your communication with the machine. It isn't about which function you call; it's about whether you are describing the process or the result.
Let's look at a concrete example. Imagine we have a list of products and we only want the ones that are in stock and cost less than $50.
const products = [
{ name: 'Keyboard', price: 40, inStock: true },
{ name: 'Mouse', price: 20, inStock: false },
{ name: 'Monitor', price: 200, inStock: true },
{ name: 'Cable', price: 10, inStock: true },
];
// The Imperative Way
const cheapAvailableProducts = [];
for (let i = 0; i < products.length; i++) {
if (products[i].inStock && products[i].price < 50) {
cheapAvailableProducts.push(products[i]);
}
}
In the snippet above, I am micromanaging the computer. I'm telling it exactly how to move: "Create an empty array. Start a counter at zero. Check if the counter is less than the length. Increment the counter. Access the element at this specific index. Check these two conditions. Push the result." This is Imperative style. It's a recipe; it's a list of step-by-step instructions.
Declarative is about "What", Imperative is about "How"
Now, let's look at the same logic written declaratively. I'm not just using a "shortcut"—I'm changing the conversation I'm having with the JavaScript engine.
// The Declarative Way
const cheapAvailableProducts = products.filter(p => p.inStock && p.price < 50);
Notice the difference? I didn't tell JavaScript how to loop. I didn't tell it to manage an index or push items into a new array. I simply described what I wanted: "I want a filtered version of this list where the items meet these criteria." I've abstracted away the how (the looping and state management) and focused entirely on the what (the business logic).
I'll be honest: imperative code isn't "evil." Sometimes you need it for extreme performance optimizations or when you're dealing with complex break/continue logic that array methods handle poorly. But in a professional codebase, declarative code is almost always preferred. Why? Because it's significantly easier to read and less prone to "off-by-one" errors. When you come back to this code in six months, you don't want to parse a for loop to figure out what the goal was; you want to see a .filter() and know instantly that the goal was to narrow down a list.
The real takeaway here is that declarative programming is a philosophy. Whether you're using SQL to query a database or React to render a UI, you're telling the system: "This is the state I want the world to be in. You figure out the steps to get there."
📋 Practical Task
Refactoring a Manual User-Filter Loop
You've inherited a piece of legacy code that processes a list of users. The current implementation is heavily imperative, using a for loop to find users who are "admins" and then manually formatting their names into a new array. This is hard to read and maintain.
Your Goal: Refactor the following imperative block into a clean, declarative chain using .filter() and .map().
const users = [
{ id: 1, name: 'Alice', role: 'admin' },
{ id: 2, name: 'Bob', role: 'user' },
{ id: 3, name: 'Charlie', role: 'admin' },
{ id: 4, name: 'David', role: 'user' },
];
// REFACTOR THIS:
const adminNames = [];
for (let i = 0; i < users.length; i++) {
if (users[i].role === 'admin') {
adminNames.push(users[i].name.toUpperCase());
}
}
console.log(adminNames); // Expected: ["ALICE", "CHARLIE"]
Rewrite the logic so that you describe what you want (admins, then their uppercase names) rather than how to iterate and push to an array.
There are no comments for now.