在进入防抖和节流之前先简单的了解下改变this的指向,在ES5中,改变this的指向我们只要牢记一句话:this永远指向最后调用它的那个对象,那么对于this的指向问题就比较好理解了
改变this的指向的方法主要有以下几种:
使用ES6中的箭头函数
在函数内部使用 _this = this
使用apply、call、bind
new实例化一个对象
apply、call、bind 基本介绍
基本语法:
fn.apply(obj, [p1, p2, ...])
fn.call(obj, p1, p2, ...)
fn.bind(obj, p1, p2, ...)
这三个方法是挂在Function对象上的,调用这三个方法的必须是一个函数。
这三个方法的共有作用:改变函数fn的this指向。
call和apply的区别在于:传参的写法不同,apply的第2个参数是数组,call则是从第2个至第n个都是给fn的传参。
bind和上面两个方法又有所不同,bind虽然改变了fn的this指向,但不是马上执行,而apply和call是在改变了this指向后立即执行。
防抖
触发高频率时间后n秒函数只会执行一次,如果n秒内高频事件再次触发,则重新计算时间
防抖的场景
1.登录、发短信、模糊查询等按钮避免用户点击太快,以至于发送多次请求,需要防抖
2.调整浏览器窗口大小时,resize此时过于频繁,造成计算过多,此时需要一次到位,就用到了防抖
3.文本编辑器实时保存,当无任何更改操作疫苗后进行保存
<body>
<input id="search" type="text">
</body>
<script>
function debounce(fun,wait){
let timeOut = null;//外部局部变量
return function(){//闭包
if(timeOut) clearTimeout(timeOut)//去掉之前的无效任务
// 创建新的任务
timeOut = setTimeout(()=>{
// fun() //直接执行函数,作用域容易出现问题
fun.apply(this,arguments)
// call apply 可以改变函数的作用域
// 第一个参数是指定作用域
// call(obj,1,2,3)
// apply(obj,[1,2,3]) 参数为数组
},wait)
}
}
function count(){
console.log("调用成功")
}
search.onkeyup = debounce(count,2000)
</script>
节流
高频事件触发,但在n秒内只会执行一次,所以节流会稀释函数的执行频率
节流场景
1.scroll事件,每隔一秒计算一次位置信息等
2.浏览器播放事件,每隔一秒计算进度信息等
3.input框实时搜索并发请求展示下拉列表,每隔一秒发送一次请求(也可以做防抖)
<body>
<div id="content" style="height: 500px;width:300px;background-color: aqua;"></div>
</body>
<script>
function count(){
console.log("调用成功")
}
//方法1 setTimeout
function throttle(fun,wait){
let timeOut = null;
return function (){
if(!timeOut){
timeOut = setTimeout(()=>{
timeOut = null //清除任务
fun.apply()
},wait)
}
}
}
//方法2固定时间,使用时间戳计算
function throttle2(fun,wait){
let p = 0;
return function(){
let now = Date.now()//当前时间
if(now - p > wait){
fun.apply(this,arguments)
// 重置p
p = now;
}
}
}
//content.onclick = throttle(count,2000)
content.onclick = throttle2(count,2000)
</script>
防抖和节流区别
防抖是触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间。适用于可以多次触发但触发只生效最后一次的场景。
节流是高频事件触发,但在n秒内只会执行一次,如果n秒内触发多次函数,只有一次生效,节流会稀释函数的执行频率。