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)
37: Function Currying
You've likely seen functions that take three or four arguments. They work fine, but they can get repetitive if you find yourself passing the same first two arguments over and over again. That's where currying comes in. It's not magic; it's just a way of rearranging how your functions receive their data.
What exactly is currying, and why not just pass all the arguments at once?
At its simplest, currying is the process of taking a function that accepts multiple arguments and turning it into a series of functions that each take one argument. Instead of f(a, b, c), you get f(a)(b)(c).
Now, you're probably thinking, "Why on earth would I want to call a function three times instead of once?" The power is in partial application. It allows you to "lock in" some arguments and create a new, more specialized function that you can reuse throughout your app.
// The "standard" way
const multiply = (a, b) => a * b;
console.log(multiply(2, 5)); // 10
console.log(multiply(2, 10)); // 20
// The curried way
const curriedMultiply = (a) => (b) => a * b;
const double = curriedMultiply(2); // 'a' is now locked as 2
console.log(double(5)); // 10
console.log(double(10)); // 20
In the example above, double is a specialized version of curriedMultiply. I didn't have to pass the 2 every single time. I created a tool specifically for doubling numbers.
How do I actually write this without getting lost in the syntax?
If you're using older function declarations, it looks like a set of Russian nesting dolls. But with arrow functions, it becomes a very clean, one-line chain. I almost always use arrow functions for currying because it makes the "flow" of data much easier to visualize.
Let's look at a real-world scenario: a logging system. Imagine you want to log messages, but you want to specify the severity (INFO, WARN, ERROR) and the component (API, UI, AUTH) before you actually log the message.
const logger = (severity) => (component) => (message) => {
return `[${severity}] [${component}]: ${message}`;
};
// We can create a specialized logger for API errors
const apiError = logger('ERROR')('API');
console.log(apiError('Connection timeout')); // [ERROR] [API]: Connection timeout
console.log(apiError('Invalid API Key')); // [ERROR] [API]: Invalid API Key
// Or a logger for UI info
const uiInfo = logger('INFO')('UI');
console.log(uiInfo('Button clicked')); // [INFO] [UI]: Button clicked
Is this just a fancy academic trick, or does it actually save time?
It's definitely not just for showing off in interviews. I use this constantly when dealing with configuration or event handling. Whenever you have a set of "configuration" arguments that rarely change, and "data" arguments that change every time the function is called, currying is your best friend.
Think about it like this: currying lets you build a pipeline. You configure the function once at the top level of your application, and then you pass that configured function down to your components or helper modules. Those components don't need to know about the configuration; they just provide the final piece of data.
One thing to keep in mind: don't overdo it. If you're only ever going to call a function once with all its arguments, currying just adds unnecessary boilerplate. Use it when you see a pattern of repetition.
📋 Practical Task
Build a Regional Tax Calculator
You are building a checkout system for a store that operates in multiple countries. Each country has a different tax rate, and each product category has a different luxury surcharge. You need to create a curried function to handle this without repeating the tax rates for every single item.
Requirements:
- Create a curried function called
calculatePricethat takes three arguments in this order:taxRate,surcharge, andprice. - The final returned value should be:
price + (price * taxRate) + surcharge. - Use this curried function to create a specialized function called
ukElectronics. This specialized function should have ataxRateof0.20(20%) and asurchargeof5. - Test your
ukElectronicsfunction by passing it a price of100. The result should be125.
There are no comments for now.