从防抖函数到闭包、高阶函数

671 阅读2分钟

作为一名开发,不仅要具备使用各种工具的能力,还需要经常学习了解各种各样概念。概念学习很是枯燥,经常是看到一半就放弃,就算硬着头皮看完也稀里糊涂(这是讲了个什么来着,用到哪里去,为什么这么用)。所以本篇文章的思路是从实践应用着手,理解那些曾经看过却又懵懂的概念。

今天心血来潮,想着实现一个防抖函数,于是乎就有了以下的渣渣代码。

防抖:在指定时间(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函数。那么观察一下以上代码的妙处:

  1. 将timer创建到debounce内部
  2. 将改进前的debounce包装在return function 内部

闭包

btn绑定点击事件时,绑定的是debounce返回的return 函数。当点击页面中的按钮,触发点击事件click执行,进而行成了对debounce函数作用域中timer的应用,这就形成了一个闭包

高阶函数

那么高阶函数体现在哪里?首先回忆一下高阶函数的概念。

  1. 接受一个或多个函数作为参数输入
  2. 返回一个新的函数 满足以上一个条件的函数就是高阶函数,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)
}

如有错误,欢迎各路大神指正。