Understanding Closures and Currying in JavaScript: Functional Programming Essentials
This article explains how closures and currying form the core of JavaScript functional programming, demonstrates multiple curry implementations, shows practical uses such as argument caching, debounce/throttle, and lodash utilities, and highlights their relevance for front‑end developer interviews.
As a JavaScript developer with five years of experience, the author reflects that the language’s core concepts are closures and asynchronous behavior, and that functional programming elegantly connects these ideas; the column therefore revisits JavaScript fundamentals from a functional perspective.
The discussion begins with the historical roots of functional programming in lambda calculus, showing a lambda expression and its JavaScript equivalent that uses a higher‑order function to return another function, illustrating that currying is essentially a “twin” of closures.
Several curry implementations are presented:
lambda x. ( lambda y. plus x y ) function add(a) {
return function(b) {
return a + b;
}
}
add(1)(2) let arr = []
function addCurry() {
let arg = Array.prototype.slice.call(arguments);
arr = arr.concat(arg);
if (arg.length === 0) {
return arr.reduce((a,b)=>{return a+b})
} else {
return addCurry;
}
}
addCurry(1)(2)(3)() function addCurry() {
let arr = [...arguments]
let fn = function() {
if(arguments.length === 0) {
return arr.reduce((a, b) => a + b)
} else {
arr.push(...arguments)
return fn
}
}
return fn
} function addCurry() {
let arr = [...arguments]
// collect all arguments via closure
var fn = function() {
arr.push(...arguments);
return fn;
};
// implicit conversion via toString
fn.toString = function() {
return arr.reduce(function (a, b) {
return a + b;
});
}
return fn;
}These variations illustrate how to avoid external mutable state, how to use implicit conversion with toString , and how mastering all three forms can pass a typical interview question on currying.
The article then explores practical curry applications:
**Caching arguments** – using a partial helper to pre‑bind parameters for an ajax call.
**Caching judgment** – wrapping a conditional function so the expensive if…else runs only once, returning a new function for repeated calls.
**Caching calculation** – a generic cached wrapper that stores results of heavy computations (e.g., large‑number loops) and returns the cached value on subsequent identical inputs.
**Caching functions** – composing simple functions ( multi10 and add100 ) via a compose helper, turning a two‑step calculation into a single curried call.
Next, the article introduces two ubiquitous higher‑order utilities:
function debounce(fn, delay) {
delay = delay || 200;
let timer = null;
return function() {
let arg = arguments;
clearTimeout(timer);
timer = setTimeout(function() {
fn.apply(this, arg);
}, delay);
}
} function throttle(fn, delay) {
delay = delay || 200;
let timer = null;
let timestamp = 0;
return function() {
let arg = arguments;
let now = Date.now();
if (timestamp === 0) {
timestamp = now;
}
clearTimeout(timer);
if (now - timestamp >= delay) {
fn.apply(this, arg);
timestamp = now;
} else {
timer = setTimeout(function() {
fn.apply(this, arg);
timestamp = 0;
}, delay);
}
}
}Both utilities rely on closures to preserve internal state ( timer , timestamp ) across calls.
The discussion then references lodash’s high‑order functions ( _.debounce , _.throttle , _.curry , _.partial , _.memoize , etc.), showing that they are concrete implementations of the patterns described earlier.
Additional examples include before and after helpers that limit function execution based on call count, further demonstrating how closures and currying enable sophisticated control flow.
In conclusion, the author emphasizes that understanding closures and currying is essential for front‑end developers; interviewers often use these concepts to differentiate junior, intermediate, and senior candidates, and mastering them leads to more reusable, elegant JavaScript code.
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.