闭包实例--函数防抖

/**
 * @function debounce 函数防抖
 * @param {Function} fn 需要防抖的函数
 * @param {Number} interval 间隔时间
 * @return {Function} 经过防抖处理的函数
 * */
function debounce(fn, interval) {
    let timer = null; // 定时器
    return function() {
        // 清除上一次的定时器
        clearTimeout(timer);
        // 拿到当前的函数作用域
        let _this = this;
        // 拿到当前函数的参数数组
        let args = Array.prototype.slice.call(arguments, 0);
        // 开启倒计时定时器
        timer = setTimeout(function() {
            // 通过apply传递当前函数this,以及参数
            fn.apply(_this, args);
            // 默认300ms执行
        }, interval || 300)
    }
}
概念:

就是指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。
通俗一点:在一段固定的时间内,只能触发一次函数,在多次触发事件时,只执行最后一次。

使用时机:
  • 搜索功能,在用户输入结束以后才开始发送搜索请求,可以使用函数防抖来实现;

闭包实例--函数节流

/**
 * @function throttle 函数节流
 * @param {Function} fn 需要节流的函数
 * @param {Number} interval 间隔时间
 * @return {Function} 经过节流处理的函数
 * */
function throttle(fn, interval) {
    let timer = null; // 定时器
    let firstTime = true; // 判断是否是第一次执行
    // 利用闭包
    return function() {
        // 拿到函数的参数数组
        let args = Array.prototype.slice.call(arguments, 0);
        // 拿到当前的函数作用域
        let _this = this;
        // 如果是第一次执行的话,需要立即执行该函数
        if(firstTime) {
            // 通过apply,绑定当前函数的作用域以及传递参数
            fn.apply(_this, args);
            // 修改标识为null,释放内存
            firstTime = null;
        }
        // 如果当前有正在等待执行的函数则直接返回
        if(timer) return;
        // 开启一个倒计时定时器
        timer = setTimeout(function() {
            // 通过apply,绑定当前函数的作用域以及传递参数
            fn.apply(_this, args);
            // 清除之前的定时器
            timer = null;
            // 默认300ms执行一次
        }, interval || 300)
    }
}
概念

就是限制一个函数在一定时间内只能执行一次。

使用时机
  • 改变浏览器窗口尺寸,可以使用函数节流,避免函数不断执行;
  • 滚动条scroll事件,通过函数节流,避免函数不断执行。

 

函数节流与函数防抖的区别:

我们以一个案例来讲一下它们之间的区别:
设定一个间隔时间为一秒,在一分钟内,不断的移动鼠标,让它触发一个函数,打印一些内容。

  • 函数防抖:会打印1次,在鼠标停止移动的一秒后打印。
  • 函数节流:会打印60次,因为在一分钟内有60秒,每秒会触发一次。
  • 总结:节流是为了限制函数的执行次数,而防抖是为了限制函数的执行时机。

函数节流与函数防抖的使用

此处使用一个对象的方法,主要为了测试this指向绑定的问题,调用的时候传递参数问题等。

function log(a,b) {
    console.log(a,b);
    console.log(this);
}
const throttleLog = throttle(log, 1000);
const debounceLog = debounce(log, 1000);
let a  = {
    b: throttleLog,
    c: debounceLog
};
document.body.onmousemove = function() {
    a.b('throttle', 'log');
    a.c('debounce', 'log');
};

 

 

闭包实例--给元素伪数组添加事件

// DOM操作
let li = document.querySelectorAll('li');
for(var i = 0; i < li.length; i++) {
    (function(i){
        li[i].onclick = function() {
            alert(i);
        }
    })(i)
}

闭包实例--不使用循环返回数组

function getArr() {
    let num = 10;
    let arr = [];
    return (function(){
        arr.unshift(num);
        num--;
        if(num > 0) {
            arguments.callee();
        }
        return arr;
    })()
}
console.log(getArr());  //[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]