Higher-Order Functions in JavaScript
What higher-order functions are, how map, filter, and reduce work under the hood, and how to write your own.
Higher-Order Functions in JavaScript
高阶函数(higher-order function)的定义很简单:接收函数作为参数,或者返回一个函数,满足其中一个就算。Array.map()、Array.filter()、Function.bind() 都是高阶函数。
但定义不是重点,重点是它解决了什么问题。
运算缺失——把「怎么做」留给调用方
map 这个函数,做的事是遍历数组,把每个元素变成新的值,然后收集起来。但「怎么变」是缺失的,这一步由外部传入:
1
2
3
4
5
6
7
8
function map(fn) {
const result = [];
for (let i = 0; i < resourceArr.length; i++) {
const newValue = fn(resourceArr[i]);
result.push(newValue);
}
return result;
}
如果把「怎么变」写死在里面,这个函数就只能做一件事。接收一个函数参数,它就能做任何变换。运算的「缺失」部分由外部填补。
运算延续——改造函数,返回更强的版本
bind 就是这种模式——接收一个 this 值,返回一个绑定了 this 的新函数:
1
2
3
4
function bind(thisArg) {
const fn = function () {}; // 改造后的函数
return fn;
}
把它理解成「给车加装备」:原来的函数能力不够,改造一下,把改造好的版本返回出去。将来任何时候调用的都是加强版。
高阶组件(HOC)就是这个思路用在了组件上——接收一个组件,加装某些逻辑(权限、数据注入等),返回一个增强过的组件。
动画函数
高阶函数的实际用途之一:写一个 JS 动画函数,让数字从 A 变到 B,至于变化时「怎么展示」留给调用方。
核心逻辑:在指定时间内匀速变化:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function animation(duration, from, to, onProgress) {
const dis = to - from;
const speed = dis / duration;
const startTime = Date.now();
let value = from;
onProgress(value);
function _run() {
const now = Date.now();
const time = now - startTime;
if (time >= duration) {
value = to;
onProgress(value);
return;
}
const d = time * speed;
value = from + d;
onProgress(value);
requestAnimationFrame(_run);
}
requestAnimationFrame(_run);
}
onProgress 是缺失的那部分——每次数字更新时做什么,调用方自己决定。点击按钮触发价格变化:
1
2
3
4
5
6
7
const label = document.querySelector("div");
const btn = document.querySelector("button");
btn.addEventListener("click", () => {
animation(1000, 2999, 299, (value) => {
label.innerHTML = `价格:${value.toFixed(2)}`;
});
});
同样的函数做倒计时,参数换一下:
1
2
3
4
animation(5000, 5, 0, (value) => {
const str = value === 0 ? "验证码" : `${value.toFixed(1)} S`;
label.innerHTML = str;
});
防抖、节流也是一样的结构——接收「原函数」和「时间间隔」,返回一个经过改造的版本。那是「运算延续」的典型例子。
This post is licensed under CC BY 4.0 by the author.