节流
一段时间内只执行一次动作
function throttle(fn,delay){ //这里是否是箭头函数没有关系
let timer = null;
return function(){ //如果这里return箭头函数,则没有this,会向上查找this,找到window
if(timer) return;
timer = setTimeout(()=>{ //这里又必须是箭头函数,不然this指向window
fn.apply(this)
timer = null
},delay)
}
}
防抖
一段时间内只执行最后一次动作
function debounce (fn,delay){
let timer = null;
return function(){
if(timer) clearTimeout(timer);
timer = setTimeout(()=>{
fn.apply(this);
},delay)
}
}
关于this的指向问题,牢记以下几点:
- 普通的
function
函数,this指向Window
,严格模式下指向undefined
; - 对象中的方法(不能是箭头函数)中,
this
指向该对象; - new 构造函数(不能是箭头函数)中,
this
指向实例对象; - HTML 事件函数(不能是箭头函数)中,
this
指向了接收事件的 HTML 元素; call
,apply
,bind
可以显示绑定this,指向当前环境的this
- 箭头函数没有this,会沿着作用域链向上查找
this
,直到找到为止。他会捕获自己在定义时(不是调用时),外层环境的this
。
所以以下代码中无法将背景颜色变为blue
const debounce = function (fn,delay){
let timer = null;
return (...args)=>{
if(timer) clearTimeout(timer);
timer = setTimeout(()=>{
fn.apply(this,args);
},delay)
}
}
c.addEventListener("click",debounce(function(){
console.log(this); //Window
console.log(`防抖+${i++}`);
this.style.backgroundColor='blue'
},2000))
解释: debounce
执行后,返回(return
)一个箭头函数,该箭头函数没有this
,会沿着定义时的作用域链向上查找this
,找到Window
,而定时器的回调函数也是箭头函数,也会向上查找,直到找到Window
,所以最终this
指向Window
可以改成下面的代码(只为了搞清楚this
指向才这样写,实际中不推荐这样写防抖)
c.addEventListener("click",function(){
console.log('1',this); //<div id="c"></div>
const debounce = (fn,delay)=>{ //将防抖函数定义在事件函数中,
//则向上查找this就是dom元素了。这里必须写成箭头函数的形式,
//才会向上查找到dom元素。写成普通函数则this还是指向window
let timer = null;
console.log('2',this); //<div id="c"></div>
return (...args)=>{
if(timer) clearTimeout(timer);
timer = setTimeout(()=>{
fn.apply(this,args);
},delay)
}
}
debounce(function(){
console.log('3',this); //<div id="c"></div>
console.log(`防抖+${i++}`);
this.style.backgroundColor='blue'
},2000)() //要加括号是因为,这里不是回调函数。
//回调函数不用加括号会自己执行,但普通函数不行
})
另外, 不管是对象的方法、事件函数还是构造函数,this
的指向只在当前函数中有作用,在嵌套函数中会失效,比如
var person = {
firstName: "John",
lastName : "Doe",
id : 5566,
fullName : function(){
console.log(this);
function test(){
console.log('2',this.firstName + " " + this.lastName); //undefined undefined
}
test()
return this.firstName + " " + this.lastName;
}
};
console.log('1', person.fullName()); //John Doe
此时,fullName
方法中的this
指向person
对象,test
函数中的this
还是指向Window
,若将test
改为箭头函数,则其会向上找到对象中的this
。