常用的高阶函数 | 青训营笔记

115 阅读2分钟

这是我参与「第四届青训营 」笔记创作活动的第2天

一些常用的高阶函数分享~~~

高阶函数(HOF)

以函数作为参数,以函数作为返回值,通常用于装饰器。 其一般形式为👇

function HOF(fn) {
  return function(...args) {
    return fn.apply(this, args);
  }
}

如果没有添加其他 js 语句,执行 HOF(fn)() 与执行 fn() 是一样的。 使用高阶函数有助于进行过程抽象,将原本的非纯函数转化为纯函数,防止对外界造成干扰。

常用的高阶函数有:Once, throttle, debounce。

Once —— 只执行一次

在一些只想执行一次代码的场合,比如为 button 添加点击事件,2秒后删除本节点,这时候如果重复点击 button 就会报错,使用 Once 函数可以解决这个问题,只能点击一次。

function once(fn) {
  return function(...args) {
    if (fn) {
      let res = fn.apply(this, args);
      fn = null;
      return res;
    }
  }
}

throttle —— 节流函数

在一段时间内只执行一次,重复触发无效,通常用于鼠标移动等连续触发的事件中,可以很好的节约性能。 节流函数有两种实现方式,一种根据时间戳,一种利用定时器。

// 时间戳写法
    function throttle(fn, wait) {
      let pre = +new Date();
      return function (...args) {
        let now = +new Date();
        if (now - pre >= wait) {
          pre = now;
          return fn.apply(this, args);
        }
      }
    }
// 定时器写法
    function throttle(fn, wait) {
      let timer = null;
      return function (...args) {
        if (!timer) {
          timer = setTimeout(() => {
            timer = null;
          }, wait);
          return fn.apply(this, args);
        }
      }
    }

debounce —— 防抖函数

同样是一段时间内只执行一次,与节流的区别是:节流函数在指定时间段内不断触发一定会执行一次,而防抖函数如果不停触发,每次都会重新计时,直到指定时间段内没有新的触发。两次执行的时间间隔至少是指定时间。

function debounce(fn, wait) {
  let timer = null;
  return function (...args) {
    clearTimeout(timer);
    timer = setTimeout(() => {
      return fn.apply(this, args);
    }, wait);
  }
}

此时的防抖函数第一次触发时是不执行的,延时时间结束才会执行。如果希望第一次能够执行,可以添加一个 immediate 参数👇

function debounce(fn, wait, immediate = false) {
  let timer = null;
  return function (...args) {
    clearTimeout(timer);
    if (!immediate) {
      timer = setTimeout(() => {
        return fn.apply(this, args);
      }, wait);
    } else {
      let flag = !timer;
      timer = setTimeout(() => {
        timer = null;
      }, wait);

      if (flag) {
        return fn.apply(this, args);
      }
    }
  }
}

consumer —— (emmmm,不知道应该叫什么名字,但是很厉害的一个函数)

将每次触发的函数存在一个队列中,按照指定的时间依次调用,不会丢失其中的任一触发。

function consumer(fn, time) {
  let tast = [];
  let timer = null;

  return function(...args) {
    tast.push(fn.bind(this, ...args));

    if (timer === null) {
      timer = setInterval(() => {
        tast.shift().call(this);
        if (tast.length <= 0) {
          clearInterval(timer);
          timer = null;
        }
      }, time);
    }
  }
}