这是我参与「第四届青训营 」笔记创作活动的第6天
本文主要介绍写好JS的第三个重要方面——过程抽象。过程抽象可以提升系统的可维护性,同时简化代码的额外处理逻辑,减少逻辑陷阱。
概念解析
什么是过程抽象
为了能够让“只执行一次“的需求覆盖不同的事件处理,我们可以将这个需求剥离出来。这个过程我们称为过程抽象。
- 用来处理局部细节控制的一些方法
- 函数式编程思想的基础应用
什么是高阶函数
高阶函数(HOF)是对其他函数进行操作的函数,操作可以是将它们作为参数,或者是返回它们。 简单来说,高阶函数是一个接收函数作为参数或将函数作为输出返回的函数。
- 以函数作为参数
- 以函数作为返回值
- 常用于作为函数装饰器
高阶函数的返回函数恰好可以对其进行包装,承载抽象出来的过程及连接原来函数的参数和作用域,帮助实现过程抽象。
function HOF0(fn) {
return function(...args) {
return fn.apply(this, args);
}
}
常见的高阶函数
Once
单次执行(once),我们有时会遇到事件处理函数只能执行一次的情况,此时就是once函数发挥作用的时候了。
function once(fn) {
return function(...args) {
if(fn) {
const ret = fn.apply(this, args);
fn = null;
return ret;
}
}
}
Throttle
节流函数(throttle),就是用于防止频繁的执行操作,限制执行的频率,(比如向服务器发送数据)。在某段时间内,不管你触发了多少次回调,都只认第一次,并在计时结束时给予响应。
function throttle(fn, time = 500){
let timer;
return function(...args){
if(timer == null){
fn.apply(this, args);
timer = setTimeout(() => {
timer = null;
}, time)
}
}
}
btn.onclick = throttle(function(e){
circle.innerHTML = parseInt(circle.innerHTML) + 1;
circle.className = 'fade';
setTimeout(() => circle.className = '', 250);
});
节流应用场景
- 按钮点击事件
- 拖拽事件
- onScoll
- 计算鼠标移动的距离(mousemove)
debounce
防抖函数(debounce),实现的是取消(防止)多余的执行操作,只保留最后一次的执行。也就是如果事件(极短的时间内)连续触发多次,防抖函数可以防止多次(重复无用的)执行,只保留最后一次的操作。
比如下面代码示例,我们想让屏幕上的小鸟跟随我们鼠标移动的方向进行移动,但是又不希望在鼠标乱晃移动的过程中同样跟随,而是希望它在鼠标移动结束处于稳定状态时,向着鼠标最终所在位置进行移动,这时防抖函数(debounce)就可以派上用场了。
var i = 0;
setInterval(function(){
bird.className = "sprite " + 'bird' + ((i++) % 3);
}, 1000/10);
function debounce(fn, dur){
dur = dur || 100;
var timer;
return function(){
clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this, arguments);
}, dur);
}
}
document.addEventListener('mousemove', debounce(function(evt){
var x = evt.clientX,
y = evt.clientY,
x0 = bird.offsetLeft,
y0 = bird.offsetTop;
console.log(x, y);
var a1 = new Animator(1000, function(ep){
bird.style.top = y0 + ep * (y - y0) + 'px';
bird.style.left = x0 + ep * (x - x0) + 'px';
}, p => p * p);
a1.animate();
}, 100));
防抖应用场景
- 搜索框输入查询,如果用户一直在输入中,没有必要不停地调用去请求服务端接口,等用户停止输入的时候,再调用,设置一个合适的时间间隔,有效减轻服务端压力。
- 表单验证
- 按钮提交事件。
- 浏览器窗口缩放,resize事件(如窗口停止改变大小之后重新计算布局)等。
Thinking
为什么要使用高阶函数?
使用函数式编程思想中的高阶函数能够设计出简单可靠的API,这些高阶的API根据确定参数返回确定的函数,它们依然是纯函数,使得它们对简化系统,提升可扩展性和可维护性都有着非常大的帮助,同时高阶函数可以任意组合,形成强大的功能。
编程范式
命令式与声明式
//命令式编程
let list = [1, 2, 3, 4];
let mapl = [];
for(let i = 0; i < list.length; i++) {
mapl.push(list[i] * 2);
}
//声明式编程
let list = [1, 2, 3, 4];
const double = x => x * 2;
list.map(double);
编程范式总结
- 过程抽象 / HOF / 装饰器
- 命令式 / 声明式