手写防抖和节流中的一些细节

使用函数节流与函数防抖的目的,就是为了节约计算机资源,提升用户体验。js中的一些事件如浏览器的resize、scroll,鼠标的mousemove、mouseover,input输入框的keypress等事件在触发时,会不断地调用绑定在事件上的回调函数,极大地浪费资源,降低前端性能。为了优化体验,需要对这类事件进行调用次数的限制。

防抖:短时间内大量触发,但只执行一次。原理:设置定时器,delay时间后执行事件处理,期间每次触发事件都会将定时器重置,直到delay时间内无第二次事件触发。

function debounce (func, delay) {
	let task = null
	return function (...args) {
		if (task) {
			clearTimeout(task)
		}
		task = setTimeout(() => {
			func.apply(this, ...args)
		}, delay)
	}
}



// 使用
let debounceFunc = debounce(scrollEvent, 300)
document.getElementById("my_input").addEventListener("keydown", function () {
      debounceFunc(456)
})
function scrollEvent(args) {
  console.log("滚动" + args);//滚动456
}

节流:隔一段时间执行一次,期间被多次触发也不管。实现原理:设置定时器,delay时间后执行事件处理,当事件执行完后清除定时器。

	function throttle (func, delay) {
		let task = null
		return function (...args) {
			if (!task) {
				task = setTimeout (() => {
					task = null
					func.apply(this, ...args)
				}, delay)
			}
		}
	}



// 使用
let throttleFunc = throttle(scrollEvent, 300)
document.addEventListener("scroll", function () {
  throttleFunc(123)
})
function scrollEvent(args) {
	console.log("滚动" + args);
}

对于两函数中的func.apply(this, ...args),之前感觉一直没弄清楚,于是查了很多资料,以下是自己的分析。

知识点详解:

1.定时器回调函数中的this指向问题:

(1)如果没有特殊指向,setInterval和setTimeout的回调函数中this的指向都是window。这是因为JS的定时器方法是定义在window下的。

(2)call,apply,bind可以修改this指向

(3)箭头函数没有自己的this,它的this继承自外部函数的作用域。

因此上面代码setTimeout中的this继承外层匿名函数的this,也就是节流和防抖函数的调用者。

2.apply方法的使用

Function.apply(obj,args)可将函数的this对象指向obj,args则为函数的输入参数,以数组形式传入。

上面代码中func.apply(this, ...args)则是将func的this指向改为setTimeout中的this,也就是将func的this指向改为节流和防抖函数的调用者。

上文所写的节流和防抖函数的返回值是一个函数,因此在调用时可以给其传参,输入参数可以使用剩余参数语法function (...args)写入返回的匿名函数中,并利用func.apply(this, ...args)的第二个参数传给func。

上一篇:unity 解决图片无法拖进场景的问题


下一篇:71.call和apply