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)
111: Partial Application
I see this mistake all the time when developers start building more complex event-driven systems. They have a general-purpose function and they want to use it in a specific context, but they end up triggering the function immediately instead of scheduling it for later.
function logEvent(category, message) {
console.log(`[${category}] ${message}`);
}
const saveButton = document.querySelector('#save');
const deleteButton = document.querySelector('#delete');
// I want the save button to log as 'SYSTEM'
// and the delete button to log as 'CRITICAL'
saveButton.addEventListener('click', logEvent('SYSTEM', 'User saved changes'));
deleteButton.addEventListener('click', logEvent('CRITICAL', 'User deleted record'));
The "Immediate Execution" Trap
If you ran the code above, you'd notice two things: first, the console logs 'SYSTEM' and 'CRITICAL' the moment the page loads. Second, when you actually click the buttons, nothing happens. Why?
The problem is that by writing logEvent('SYSTEM', 'User saved changes'), you aren't giving the event listener a function to call later. You are calling the function right now and handing the event listener the result of that call. Since logEvent doesn't return anything, you've effectively written addEventListener('click', undefined).
Creating Specialized Functions with .bind()
This is where partial application comes in. Partial application is the act of taking a function with multiple arguments and "fixing" some of them to create a new, more specialized function.
In JavaScript, the most direct way to do this is using .bind(). The first argument of .bind() sets the this context (we'll use null here since we don't need a specific context), and every argument after that becomes "pre-filled" in the original function.
function logEvent(category, message) {
console.log(`[${category}] ${message}`);
}
// We "partially apply" the category argument.
// These are now functions waiting to be called.
const logSystem = logEvent.bind(null, 'SYSTEM');
const logCritical = logEvent.bind(null, 'CRITICAL');
saveButton.addEventListener('click', () => logSystem('User saved changes'));
deleteButton.addEventListener('click', () => logCritical('User deleted record'));
Now, logSystem is a brand new function that only needs one argument (the message) because 'SYSTEM' is already baked into it. I personally find this much cleaner than writing the full logEvent('SYSTEM', ...) call every single time throughout a large file.
The Modern Alternative: Closures
While .bind() is the classic approach, most of the engineers I work with these days prefer using arrow functions to achieve partial application. It's often more readable and avoids the awkward null argument for the context.
const logSystem = (message) => logEvent('SYSTEM', message);
const logCritical = (message) => logEvent('CRITICAL', message);
Under the hood, this is doing the same thing: it's capturing the 'SYSTEM' string in a closure and returning a function that uses it. Whether you use .bind() or an arrow function, the goal is the same: reducing the arity (the number of arguments) of a function to make it more reusable and less error-prone.
📋 Practical Task
Building a Specialized API Request Tool
You are building a dashboard that fetches data from two different API categories: users and posts. Instead of passing the base URL and the category every time you make a request, you need to use partial application to create specialized helper functions.
Your Task:
- Start with this general function:
function apiRequest(baseUrl, category, endpoint) { return `Fetching from ${baseUrl}/${category}/${endpoint}...`; } - Use
.bind()or an arrow function to create a specialized function calledfetchUser. This function should have'https://api.example.com'and'users'already applied. - Create another specialized function called
fetchPost. This function should have'https://api.example.com'and'posts'already applied. - Test your new functions by calling
fetchUser('profile')andfetchPost('123'). They should return the correct full URL strings.
There are no comments for now.