作为一名开发,不仅要具备使用各种工具的能力,还需要经常学习了解各种各样概念。概念学习很是枯燥,经常是看到一半就放弃,就算硬着头皮看完也稀里糊涂(这是讲了个什么来着,用到哪里去,为什么这么用)。所以本篇文章的思路是从实践应用着手,理解那些曾经看过却又懵懂的概念。
今天心血来潮,想着实现一个防抖函数,于是乎就有了以下的渣渣代码。
防抖:在指定时间(delay)内,只触发一次
<button onclick="debounce(doSomething , 3000)">防抖</button>
<script>
var timer = null
function debounce(fn, delay) {
clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(this)// fn dosomething
}, delay);
}
function doSomething() {
console.log('业务逻辑doing');
}
</script>
以上代码,实现了一个简单的防抖,可是移植性很差。一处使用,全局暴露一个timer,那么两处、三处呢?在全局新增多个timer吗?再者如果团队共享呢,要让使用的人各自在全局增添timer吗?不合适。那改进一下:
<button id="btn">防抖</button>
<button id="btn2">防抖2</button>
<script>
var btn = document.getElementById('btn')
var btn2 = document.getElementById('btn2')
btn.onclick = debounce(dosomething, 3000)
btn2.onclick = debounce(dosomething2, 3000)
function debounce(fn, delay) {
let timer = null
return function () {
clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(this)// fn dosomething
}, delay);
}
}
function dosomething() {
console.log('业务逻辑')
}
function dosomething2() {
console.log('业务逻辑2')
}
</script>
运行以上代码,实现了一个可复用的防抖函数debounce,仅且只在全局只暴露了一个debounce函数。那么观察一下以上代码的妙处:
- 将timer创建到debounce内部
- 将改进前的debounce包装在return function 内部
闭包
btn绑定点击事件时,绑定的是debounce返回的return 函数。当点击页面中的按钮,触发点击事件click执行,进而行成了对debounce函数作用域中timer的应用,这就形成了一个闭包。
高阶函数
那么高阶函数体现在哪里?首先回忆一下高阶函数的概念。
- 接受一个或多个函数作为参数输入
- 返回一个新的函数 满足以上一个条件的函数就是高阶函数,debounce 满足以上两者,就是一个高阶函数。再仔细一想,其实我们已经用过很多高阶函数了。比如:Array.prototype.sort、Array.prototype.filter......原来高阶函数一点都不高冷,很接地气,所以不能被概念的纸老虎吓到😄
终极防抖函数实现
到这里,我们继续优化一下防抖函数,比如点击事件传参怎么办?继续改进代码如下
<button id="btn">防抖</button>
<script>
var finnalDo = debounce(dosomething, 3000)
document.getElementById('btn').onclcik = finnalDo('params')
function debounce(fn, delay) {
let timer = null
return function (...args) {
clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(this, args)// fn dosomething
}, delay);
}
}
function dosomething(params) {
console.log('业务逻辑' + params)
}
如有错误,欢迎各路大神指正。