高阶函数、声明式和命令式编程
高阶函数、命令式编程和声明式编程
什么是高阶函数?
- 以函数作为参数
- 以函数作为返回值
- 常用于函数装饰器
1 | let HOFO = function (fn) { |
高阶函数的好处
- 高阶函数的魅力在于它的可重复利用性,如果不是高阶函数,
map
、filter
、reduce
等强大的数组函数就不可能存在。 - 使 JavaScript 适合函数式编程的原因是它接受高阶函数。
常用高阶函数示例
防抖和节流
节流: n 秒内只运行一次,若在 n 秒内重复触发,只有一次生效
once
让函数只执行一次,常用于节流
```js
let once = function (fn) {
return function (…args) {if (fn) { setTimeout(() => { fn = null; }); return fn.apply(this, args); }
};
};1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- throttle
- 让函数在执行后的一段时间不能被再次触发
- ```js
let throttle = function (fn, time = 500) {
let timer;
return function (...args) {
if (timer == null) {
fn.apply(this, args);
timer = setTimeout(() => {
timer = null;
}, time);
}
};
};
consumer
将多次触发的任务加入任务队列,依次间隔执行
```js
function consumer(fn, time){
let tasks = [],timer;
return function(…args){
tasks.push(fn.bind(this, ...args)); if(timer == null){ timer = setInterval(() => { tasks.shift().call(this) if(tasks.length <= 0){ clearInterval(timer); timer = null; } }, time) }
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#### 防抖: n 秒后在执行该事件,若在 n 秒内被重复触发,则重新计时
- debounce
- ```js
let debounce = function (fn, time) {
let timer;
return function (...args) {
clearTimeout(timer);
timer = setTimeout(() => {
return fn.apply(this, args);
}, time);
};
};
非纯函数和纯函数(pure function)
什么是纯函数和非纯函数
纯函数是指在给定输入的参数下,输出总是确定的,不依赖于外界环境
例如:
1
2let add = (a, b) => a + b;
//add返回的值只与输入参数有关
非纯函数依赖上下文
例如:
1
2
3let count = 0;
let add = () => count++;
//add返回的值依赖于count的值
如果代码中非纯函数过多,代码会变得难以维护,所以我们要减少写出非纯函数
将非纯函数转化为纯函数
1 | const isIterable = obj => obj != null |
这里的iterative和isIterable都是纯函数,它们能方便地对可迭代对象批量执行函数
例如假如现在有一个setColor
函数能改变元素的颜色,如果这时我们要对元素批量执行,再定义一个setColors
的话就产生了两个非纯函数,而如果我们利用上面的iterative
函数就可以直接将setColor
函数传入其中,实现批量操作,减少了非纯函数的产生。
命令式和声明式编程
以改变一个按钮的状态为例
命令式编程关注怎么做
- ```js
switcher.onclick = function(evt){
if(evt.target.className === ‘on’){
}else{evt.target.className = 'off';
}evt.target.className = 'on';
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
- 声明式编程关注做什么
- ```js
function toggle(...actions){
return function(...args){
let action = actions.shift();
actions.push(action);
return action.apply(this, args);
}
}
switcher.onclick = toggle(
evt => evt.target.className = 'off',
evt => evt.target.className = 'on'
);
- ```js
看起来区别不大但当这个按钮有三种状态时,在命令式编程下我们需要重写if-else的逻辑,而声明式编程下我们只需要在toggle
里再多传入evt => evt.target.className = 'warn'
就可以实现。