最近也是在准备面试,对于我自己来说过不去的坎除了算法就是手写题了,认认真真的准备了,那么下面这些细节你注意到了么~
1.防抖
1.1 防抖怎么写
防抖是啥?就是让一个函数一段时间内只执行一次,最常见的案例就是表单的提交按钮以及页面大小的调整,这里我打断一下,贴一下,我找到的关于 event 对象的几个坐标属性的图,细节一波—> 传送门
回归正题,一段时间执行一次,一听咱就反应过来了,这要用定时器啊,是的,大佬们是这么写的。
<button id="button">按钮</button>
<script>
const button = document.getElementById('button')
function debonce(fn,time){
let timer
return function(){
clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(this,arguments)
console.log('测试',arguments)
},time)
}
}
button.addEventListener('click',debonce(function(event){console.log('我来了',event,this)},2000))event
</script>
1.2 理解防抖
我们给一个按钮写了一个防抖,监听它的点击事件,写了一个 debonce 函数,这个函数返回一个匿名函数,DOMaddEventListener 的第二个参数应该是一个函数名,点击事件发生的时候 DOM 会帮我们调用这个函数,上边在 addEventListener 里面我们的 debonce 函数带了括号参数,所以点击事件发生后,真正执行的是 debonce 里面的匿名函数。这种写法我理解的没错的话,就是柯里化。通过在函数内返回一个函数,来连续调用,连续获得参数。
通过柯里化,我们能够在匿名函数内拿到 fun 和 time 写一个定时器,将 fun 在定时器内执行,同时在每次定时器启动时,先清理定时器,我们传的是2秒,这就保证 fn 函数执行的最短间隔是2秒,你如果一直疯狂点,只要间隔事件时间没有超过两秒,最终也只会执行最后一次。,那第一遍调用都没有定时器,清理啥呢?所以我们在匿名函数外,定义一个 time 利用闭包,即使 debonce 函数执行完了,匿名函数用到了它,就不会清除。以上就是对于防抖的普遍认知。下面再写一些细节
1.3 防抖细节
1.3.1 this
this,说到底,最终起作用的函数,还是 fn ,我们要保证 fn 里面的 this 是正常的,怎样才是正常的呢,我觉得三句话可以概括
- 谁调用,
this就指向谁,普通函数中的this指向window,严格模式下是undefined - 构造函数用到了
new操作符,函数中的this,指向新生成的对象 - 箭头函数中的
this是外层接触到的第一个this
如果不用 apply 执行的时候 fn 里面的 this 是指向 window 的,正常情况下要指向button ,所以我们使用 apply 改变 fn 中的 this 指向。
applycallbind都是定义在原型上的,能够改变函数的this指向,第一个参数就是你想把this指向哪,后面的参数,是传给调用函数的,一些区别就是传参的不同,apply将所有要传的参数,放进一个数组,call和bind则是该怎么传,还有一个区别是,调用call,apply后函数是理解执行的,bind则是返回一个新的函数。
fun1.call(bb,11,22);
fun1.apply(bb,[11,22]);
fun1.bind(bb,11,22)()
1.3.2 arguments
arguments 是一个类数组,instanceof 一下 你会发现,它不是对象是数组,但它又有 length 属性,能够通过下标拿值。通过 arguments 能够拿到 实参。
function app(){
console.log(arguments)
}
app(1,2,3,4)
另外,和 this 一样,箭头函数里面的 auguments 也是外层接触到的第一个的
function app(){
const fn = (a,b,c,d) => {
console.log('我是直接打印参数',a,b,c,d)
console.log('我是arguments对象',arguments)
}
fn(5,6,7,8)
}
app(1,2,3,4,5)
所以这个 arguments 的作用是啥呢?开头这个例子,点击按钮后,因为监听了,它调用我们的函数的时候,是会把事件对象给到我们,但给到的是匿名函数,真正要用的是 fn 所以就用到了 argument.说到底,就是帮助我们拿到执行函数的参数,我把事件监听改成自己调用,你可能就明白了
debonce(function(params){console.log('我来了',params),console.log('我是this',this)},2000)('你好啊')
怎么样?应该够细吧,哈哈哈哈~
2. 节流
节流,说实话和防抖挺像的,来看一个实际案例,监听滑轮滚动
<div style="background-color: red;width:30px;height:2000px"></div>
<script>
const fn = function(){
console.log('我触发执行了')
}
document.addEventListener('scroll',fn)
</script>
我不想让它触发这些这么多次,而是3秒里面只执行一次,要怎么写呢,看到了两种,一种是利用时间戳,一种还是用定时器。
<div style="background-color: red;width:30px;height:2000px"></div>
<script>
const fn = function(event){
console.log('我触发执行了',event)
}
const throttle = function(fn,wait){
let time1 = 0
return function(){
let time2 = new Date()
if(time2-time1 >wait){
fn.apply(this,arguments)
time1 = time2
}
}
}
document.addEventListener('scroll',throttle(fn,1000))
</script>
我自己感觉,从目的上来说,我感觉不到防抖和节流有很大的区别,但是从代码上说的话,防抖没超过时间间隔,会清理定时器,所以执行的都是最新的函数,节流的的话,没超过时间间隔,就不执行,要等到前一个函数执行了,才能执行下一个。
后面还会写其他手写题,写这种博客收益最大的就是自己了,可能对于新手帮助会大一些,对于大佬们来说,就有点过家家了,见谅,精神食粮,欢迎食用!