一、什么是高阶函数?
一句话:
高阶函数 = 把函数当数据用的函数
只要满足下面任意一条,它就是高阶:
- 接收一个或多个函数作为参数
- 返回一个函数
二、为什么你要关心?
| 维度 | 传统写法 | 高阶函数写法 |
|---|---|---|
| 复用 | 复制粘贴 | 抽象一次,处处调用 |
| 可读 | 命令式嵌套 | 声明式管道,像读句子 |
| 测试 | 需要 mock 整块逻辑 | 纯函数粒度小,测单点 |
| 扩展 | 改老代码 | 加新函数,无侵入 |
三、日常开发 5 大“现成”高阶函数
// 1. map:映射
[1, 2, 3].map(x => x * 2); // [2, 4, 6]
// 2. filter:过滤
[55, 80, 95].filter(s => s >= 60); // [80, 95]
// 3. reduce:归纳
[1, 2, 3, 4].reduce((a, b) => a + b, 0); // 10
// 4. find / some / every...
// 5. Promise.then / async 本质也是高阶
四、手写 map —— 3 分钟造轮子
function myMap(arr, fn) {
const res = [];
for (let i = 0; i < arr.length; i++) res.push(fn(arr[i], i));
return res;
}
console.log(myMap([1, 2, 3], x => x ** 2)); // [1, 4, 9]
五、进阶实战 1:防抖(debounce)
场景:输入框连续打字,停止 500 ms 后才发请求。
核心:高阶函数返回新函数,内部维护定时器状态。
const debounce = (fn, delay = 500) => {
let timer = null;
return function (...args) {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), delay);
};
};
// 使用
const search = debounce(q => fetch(`/search?q=${q}`), 500);
document.querySelector('input')
.addEventListener('input', e => search(e.target.value));
六、进阶实战 2:节流(throttle)
场景:滚动监听,每 200 ms 最多执行一次。
思路:记录上一次执行时间。
const throttle = (fn, wait = 200) => {
let last = 0;
return function (...args) {
const now = Date.now();
if (now - last >= wait) {
last = now;
fn.apply(this, args);
}
};
};
window.addEventListener('scroll', throttle(() => {
console.log('滚动触发', Date.now());
}, 200));
七、进阶实战 3:柯里化(curry)
把多参函数变成单参链式调用,轻松生成配置函数。
const curry = fn =>
function curried(...args) {
return args.length >= fn.length
? fn.apply(this, args)
: (...next) => curried(...args, ...next);
};
const add = (a, b, c) => a + b + c;
const curriedAdd = curry(add);
console.log(curriedAdd(1)(2)(3)); // 6
console.log(curriedAdd(1, 2)(3)); // 6
八、组合函数 compose:从右到左的管道
const compose = (...fns) => x =>
fns.reduceRight((v, f) => f(v), x);
// 实战:先取绝对值,再开方,再四舍五入
const pipeline = compose(Math.round, Math.sqrt, Math.abs);
console.log(pipeline(-16)); // 4
九、高阶组件(HOC):React 里的高阶函数
function withLoading(Component) {
return function ({ isLoading, ...props }) {
return isLoading ? <div>Loading...</div> : <Component {...props} />;
};
}
const ButtonWithLoading = withLoading(Button);
十、调试技巧:如何快速识别高阶函数?
- 看签名:
fn(()=>...)或() => return function - 看调用:
const newFn = xxx(fn)再newFn() - 看命名:
withXxx、createXxx、debounce、curry大概率高阶
十一、常见面试追问
- map vs forEach 区别?
map 返回新数组,forEach 无返回、只副作用。 - 防抖节流差异?
防抖合并多次为一次;节流按固定频率执行。 - 手写 Promise.all?
本质是高阶函数:接收一组函数(或 thenable)返回新 Promise。
十二、总结 & 思维导图
高阶函数
├─ 参数是函数:map / filter / reduce / debounce / throttle
├─ 返回是函数:curry / compose / withLoading
└─ 核心价值:抽象行为、延迟执行、声明式组合
记住一句话:
当你开始把函数当乐高积木,而不是死代码,你就掌握了高阶函数。
如果文章对你有帮助,点个 ⭐️ 鼓励一下!