闭包-防抖节流
闭包实例--函数防抖
/** * @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]