一、序
关于一场糟糕的面试的自我反省,平时的工作业务逻辑不复杂,很多实现直接使用了相应的库函数和工具类框架,导致关于很多知识点都是一知半解,比如针对防抖函数和节流函数的实现原理,以及其中涉及的js基础知识,this指向等问题,是值得去深入探究的,在编写一个函数时,最先要理解该函数方法实现的流程,为了解决什么问题而设计;其次理清思路,一步步去实现方法。
二、防抖函数
- 原理:在某个的时间段内,无论触发多少次回调,只执行最后一次;
- 应用场景:input标签输入onchange事件的监听
- 实现方案:使用定时器,函数第一次执行时设定一个定时器,之后调用时发现已经设定过定时器就清空之前的定时器,并重新设定一个新的定时器,如果存在没有被清空的定时器,当定时器计时结束后触发函数执行
代码实现
function debounce(fn, time) { let timer; return function() { let args = arguments; let that = this; if(timer) clearTimeout(timer); timer = setTimeout(function() { fn.apply(that, args) }, time) } }
三、节流函数
- 原理:在某段时间间隔执行一次回调函数
- 应用场景:监听滚动事件
- 实现方案:时间差 和 延时函数两种
代码实现:
// 使用时间差判断 function throttle(fn, time) { let pretime = 0; return function() { const args = arguments; let nowtime = +new Date(); if(nowtime - pretime > time) { pretime = nowtime; fn.apply(this, args); } } } // 使用延时函数实现 function throttle(fn, delay) { let timer; return function() { const args = arguments; const that = this; if(timer) return; timer = setTimeout(function() { fn.apply(that, args); timer = null; }, delay) } }
三、知识点
1、关于this指向问题
- 在以上的方法中都使用了return一个匿名函数,这样在该匿名函数中this指向window
- 在箭头函数中没有自己的this;内部this指向外层代码
使用setTimeout中的回调函数,在非严格模式下this指向window,严格模式下指向undefined
function foo() { console.log(this.id) console.log(this) setTimeout(function() { console.log(this.id) console.log(this) }, 100) } var id = 21; foo() //输出依次为:21,window,21,window foo.call({id: 42}); //输出依次为:42,{id:42},21, window //若将setTimeout改为箭头函数,则输出会不一样 function foo() { console.log(this.id) console.log(this) setTimeout(() => { console.log(this.id) console.log(this) }, 100) } foo.call({id: 84}); //84, {id:84},84, {id:84} // 使用call方法改变了foo函数运行时其函数体内this的指向,从而使箭头函数中this的指向发生变化