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)
110: Function Composition
I've seen this pattern a dozen times in code reviews. A developer has a few small, focused utility functions, and they want to use them all on a single piece of data. It usually starts out looking something like this:
const trim = (str) => str.trim();
const lowercase = (str) => str.toLowerCase();
const removeSpecialChars = (str) => str.replace(/[^a-z0-9 ]/g, '');
const prepareSearchQuery = (input) => {
return removeSpecialChars(lowercase(trim(input)));
};
console.log(prepareSearchQuery(" Hello World!!! ")); // "hello world"
The "Inside-Out" Readability Problem
Now, technically, the code above works. But it's "broken" from a maintainability perspective. Notice how you have to read the logic from the inside out? To understand what happens to the string, your eyes have to jump to the middle—trim—then move left to lowercase, and then further left to removeSpecialChars.
It's a cognitive tax. If we decide we need to add two more steps—say, removing stop-words and adding a prefix—the prepareSearchQuery function becomes a nesting nightmare. You end up with a "pyramid of parentheses" that is incredibly easy to mess up with a single missing ).
Building a Pipeline for Data Flow
The fix is to stop nesting and start composing. In functional programming, composition is the act of combining simple functions to build more complex ones. Instead of manually wrapping functions, we can create a pipe utility. I prefer pipe over compose because it reads left-to-right (or top-to-bottom), which matches how we naturally think about data moving through a system.
Here is how I usually implement it:
const pipe = (...fns) => (initialValue) =>
fns.reduce((acc, fn) => fn(acc), initialValue);
const trim = (str) => str.trim();
const lowercase = (str) => str.toLowerCase();
const removeSpecialChars = (str) => str.replace(/[^a-z0-9 ]/g, '');
// Now we define the logic as a sequence of steps
const prepareSearchQuery = pipe(
trim,
lowercase,
removeSpecialChars
);
console.log(prepareSearchQuery(" Hello World!!! ")); // "hello world"
Look at the difference. prepareSearchQuery is now just a list of operations. If I want to change the order or add a new step, I just add a line to the list. I don't have to touch any parentheses or worry about where the return statement is.
The magic here is in reduce. The pipe function takes a bunch of functions as arguments (the ...fns spread) and returns a new function. When that new function is called with an initialValue, it iterates through the array of functions, passing the result of the previous function as the input to the next one. It's essentially a conveyor belt for your data.
📋 Practical Task
Building a Price Formatting Pipeline
You are building a checkout page where raw price data from an API needs to be cleaned and formatted before being displayed to the user. The raw data is often messy (e.g., " 1250.5 ").
Your task is to create a formatPrice function using a pipe utility. Implement the following individual functions first:
trimWhitespace: Removes leading/trailing spaces.convertToNumber: Converts the string to a float.addCurrencySymbol: Takes a number and returns a string with a "$" prefix.roundToTwoDecimals: Ensures the number has exactly two decimal places (use.toFixed(2)).
Requirements:
- Implement a
pipefunction that can handle any number of functions. - Compose the
formatPricefunction so that the data flows in this order: Trim $\rightarrow$ Convert to Number $\rightarrow$ Round $\rightarrow$ Add Symbol. - Test it with the input
" 1250.5 "to ensure the final output is"$1250.50".
There are no comments for now.