青训营——JS之常用高阶函数

192 阅读3分钟

JavaScript中的高阶函数是指以函数作为参数,以函数作为返回值的函数,其常用作函数装饰器,对一些函数进行封装或者是限制。常用的高阶函数主要有以下几种。

ONCE(只能执行一次)函数的实现

有些时候我们需要一些函数只执行一次,尤其是点击事件中会经常用到,我们可以实用高阶函数once来实现这个功能。这里我列出了一个具体的实用场景,可以直接粘贴在body标签中运行。

<button id="btn">按钮</button>
<script>
    function once(fn)  {
      return function (...args) {
        if(fn){
          const ret = fn.apply(this, args)
          fn = null
          return ret
        }
      }
    }
    const btn = document.getElementById('btn')
    const clickEvent = (e) => {
      console.log('clickEvent', e)
    }
    btn.addEventListener('click', once(clickEvent))
</script>

由于闭包,once中的匿名函数里的fn变量不会被清除,即持久化保存,因此,只需要执行一次fn后,将其设置为null,即可防止fn的再次执行。

TIMES(只能执行指定次数)函数的实现

once方法限制某个过程只执行一次,我们可以扩展once的实现思路,实现一个高阶函数times(fn, count=1),让一个函数只能执行count次。

function times(fn, count=1)  {
  return function (...args) {
    if(count > 0){
      count --
      return fn.apply(this, args)
    }
  }
}

依旧利用闭包,通过变量count,进行执行次数的限制。

THROTTLE(节流)函数的实现

throttle方法限定某个函数执行的频率,或者是最大按照某个间隔去执行。其原理是使用一个延时器,在传进来的函数执行的时候,将状态赋值给timer,到达time毫秒以后才将其置空,只有timer为空的时候才允许传进来的函数执行。

const throttle = (fn, time) => {
  let timer
  return function(...args){
    if (!timer) {
      fn.apply(this, args)
      timer = setTimeout(() => timer = null, time)
    }
  }
}

DEBOUNCE(防抖)函数的实现

debounce方法限定某个方法在某个区间内连续执行,最后只会执行一次。原理是在每次执行函数之前先清空所有延时器,然后再重新延时,直到没有新的函数调用,到指定时长后,函数才会执行一次。

const Debounce = (fn, dur=100) => {
  let timer
    return function(...args){
      clearTimeout(timer)
      timer = setTimeout(() => {
        fn.apply(this, args)
      }, dur)
   }
}

ITERATIVE(迭代)函数的实现

Iterative方法消除了传入函数中,需要被处理参数的差异化。假设我们需要将某个元素,或者某一类元素的文本颜色设置为红色,我们就可以将一个元素或者包含若干个元素的数组传入函数中。

// 判断参数是否为可迭代对象
const isIterable = (object) => object !== null && typeof object[Symbol.iterator] === 'function'
  function iterative(fn) {
    return function (subject, ...args) {
      if (isIterable(subject)) {
        for(const obj in subject) fn.apply(this, [obj, ... args])
      }
      else
          fn.apply(this, [subject, ,,,args])
    }
}

CONSUMER函数的实现

Consumer函数会将需要立即连续执行的过程,按照指定的间隔,以此延迟执行。使用一个队列,先进先出,到一定间隔后才执行下一个过程。需要注意的是,当任务队列为空的时候,需要清除定时器。

function consumer(fn, time){
  let timer;
  let queue = []
  return function (...args){
    queue.push(fn.bind(this, ...args))
    if (!timer) {
      timer = setInterval(function(){
        queue.shift().call(this)
        if (queue.length === 0) {
          clearInterval(timer)
          timer = null
        }
      }, time);
    }
  }
}