一、闭包实现计数器
需求:
创建一个 createCounter 函数,每次调用返回一个计数器函数,每次调用计数器函数返回递增的数字。
示例:
const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
请你试着补全以下代码:
function createCounter() {
let count = _______;
return function () {
return _______;
};
}
✅ 正确写法应该是:
function createCounter() {
let count = 0;
return function () {
count += 1;
return count;
};
}
解释:
count是保存在闭包中的私有变量;- 每次调用返回的函数时,
count递增并返回。
二、闭包实现 once 函数
目标:
实现一个函数 once(fn),它接收一个函数 fn,返回一个新函数,只允许 fn 执行一次,后续再调用会直接返回第一次的结果。
示例:
const init = once(() => {
console.log('初始化中...');
return 42;
});
console.log(init()); // 输出:初始化中... → 返回 42
console.log(init()); // 什么都不输出,返回第一次的 42
提示思路:
你需要用闭包保存两样东西:
- 是否已经执行过?
- 执行过的返回值
请你补全以下代码:
function once(fn) {
let hasRun = false;
let result;
return function () {
if (!hasRun) {
result = fn();
hasRun = true;
}
return _______;
};
}
⏳ 请你填空:返回第一次执行的值
完整代码就是:
function once(fn) {
let hasRun = false;
let result;
return function () {
if (!hasRun) {
result = fn();
hasRun = true;
}
return result;
};
}
很好!现在我们来挑战闭包应用的进阶玩法:
三、利用闭包实现函数柯里化(Currying)
什么是柯里化?
柯里化是指:把一个接收多个参数的函数,转换成一系列每次只接收一个参数的函数。
示例对比:
普通函数:
function add(a, b, c) {
return a + b + c;
}
console.log(add(1, 2, 3)); // 6
柯里化后:
function curriedAdd(a) {
return function(b) {
return function(c) {
return a + b + c;
};
};
}
console.log(curriedAdd(1)(2)(3)); // 6
每一层返回一个函数,通过闭包“记住”前一个参数。
🧩 小练习:你来写一个柯里化版的乘法函数 multiply(a)(b)(c),返回 a × b × c
请你补全:
function multiply(a) {
return function (b) {
return function (c) {
return _______;
};
};
}
⏳ 填空:让最终返回 a * b * c
function multiply(a) {
return function (b) {
return function (c) {
return a * b * c;
};
};
}
console.log(multiply(2)(3)(4)); // 24
柯里化 + 闭包原理解析:
- 每次调用都返回一个新函数,内部通过闭包保留上一次的参数值;
- 最后一层才真正执行运算。
四、「万能柯里化器」:curry(fn),可以把任何固定参数个数的函数转换成柯里化形式
🎯 目标:
function add(a, b, c) {
return a + b + c;
}
const curriedAdd = curry(add);
console.log(curriedAdd(1)(2)(3)); // 6
console.log(curriedAdd(1, 2)(3)); // 6
console.log(curriedAdd(1)(2, 3)); // 6
思路讲解:
我们要做的是:
- 每次调用收集参数;
- 如果收集到的参数个数
< fn.length,返回一个新函数继续收; - 如果足够,就调用原函数。
你来补全:万能 curry 函数骨架
function curry(fn) {
return function curried(...args) {
if (args.length >= fn.length) {
return fn.apply(this, args);
} else {
return function (...nextArgs) {
return _________; // 补全这里
};
}
};
}
完整代码
function curry(fn) {
return function curried(...args) {
if (args.length >= fn.length) {
return fn.apply(this, args);
} else {
return function (...nextArgs) {
return curried(...args, ...nextArgs);
};
}
};
}
【总结】你刚刚学到了:
-
如何用闭包实现参数“记忆”;
-
如何用递归合并参数直到“收满”为止;
-
柯里化不仅是面试常客,还在很多库中实际使用(比如 lodash 的
_.curry)。