写好 JS 的一些原则
- 各司其责
- 组件封装
- 过程抽象
过程抽象
过程抽象是用来处理局部细节控制的一些方法,是函数式编程思想的基础应用
如下图:
操作次数限制
对操作次数进行限制一般会在 一些异步交互 和 一次性 HTTP 请求 中使用
例如下面这个例子:
这里就会出现一种情况,当点击第一个 completed 的时候,被点击的组件并没有消失,若快速点击两次,就会报错
当然,你也可以设置 addEventListener 其中的 once 参数,让监听只响应一次
现在自己实现一个 once 函数来实现这个效果
function once(fn) {
return function (...args) {
if (fn) {
const ret = fn.apply(this, args);
fn = null;
return ret;
}
};
}
const list = document.querySelector('ul');
const buttons = list.querySelectorAll('button');
buttons.forEach((button) => {
// 这里使用 once 函数
button.addEventListener('click', once((evt) => {
const target = evt.target;
target.parentNode.className = 'completed';
setTimeout(() => {
list.removeChild(target.parentNode);
}, 2000);
}));
});
现在就不会报错了
为了能够让 “只执行一次” 的需求覆盖不同的事件处理,我们可以将这个需求剥离出来。这个过程称为过程抽象。
高阶函数
高阶函数就是以函数作为参数、以函数作为返回值、常用于作为函数装饰器
// 比如这样的
function HOFO(fn) {
return function (...args) {
return fn.apply(this, args)
}
}
节流 Throttle
代码如下:
function throttle(fn, time = 500) {
let timer;
return function (...args) {
if (timer == null) {
fn.apply(this, args);
timer = setTimeout(() => {
timer = null;
}, time)
}
}
}
const btn = document.querySelector('#btn')
const circle = document.querySelector('#circle')
btn.onclick = throttle(function (e) {
circle.innerHTML = parseInt(circle.innerHTML) + 1;
});
防抖 Debounce
这里重点看 debounce 函数
function debounce(fn, dur) {
dur = dur || 100;
var timer;
return function () {
clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this, arguments);
}, dur);
}
}
Consumer
下面这个例子就是将一个同步操作变成一个异步操作,每隔一段时间再执行
核心代码:
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)
}
}
}
Iterative
核心代码:
const isIterable = obj => obj != null
&& typeof obj[Symbol.iterator] === 'function';
function iterative(fn) {
return function (subject, ...rest) {
if (isIterable(subject)) {
const ret = [];
for (let obj of subject) {
ret.push(fn.apply(this, [obj, ...rest]));
}
return ret;
}
return fn.apply(this, [subject, ...rest]);
}
}
纯函数
什么是纯函数?
A pure function is a magic box that always gives you back the same output for a given input.
纯函数就是是一个魔术盒,它总是为给定的输入返回相同的输出
例如这个函数就是一个纯函数:
function add(a, b) {
return a + b;
}
add(1, 2) // 3
add(1, 2) // 3
所以那些 HOF0 等价范式拓展出来的高阶函数都是纯函数
编程范式
编程范式可以分成 命令式与声明式
例如这两段代码
// 命令式
let list = [1, 2, 3, 4];
let map1 = [];
for (let i = 0; i < list.length; i++) {
map1.push(list[i] * 2)
}
// 声明式
let list = [1, 2, 3, 4]
const double = x => x * 2;
list.map(double)
Toggle 切换状态案例
// 命令式
switcher.onclick = function (evt) {
if (evt.target.className === 'on') {
evt.target.className = 'off';
} else {
evt.target.className = 'on';
}
}
// 声明式
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'
);
看上去都可以实现,但是声明式的代码更有扩展性
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 = 'warn',
evt => evt.target.className = 'off',
evt => evt.target.className = 'on'
);
最后
到此,月影老师所说的写好 JS 的三个原则就介绍完了,但是目前看来还得多多练习🤣
之前的文章:
若有不当之处,欢迎评论指出