1、Thread类
838 2023-04-03 02:34:44
//为鼠标移动事件添加防抖函数 box.addEventListener('mousemove', debounce(move, 300)) // 自定义防抖函数 function debounce(fun, delay) { console.log(this); //window }
防抖函数中,当在addEventListener中想调用函数时带参 就应该考虑到一个问题就是this指向 , 此时直接在自定义函数中打印this,发现this指向的为全局的window
//为鼠标移动事件添加防抖函数 box.addEventListener('mousemove', debounce) // 自定义防抖函数 function debounce(fun, delay) { console.log(this); //box }
而防抖函数中,我们需要的this是需要指向调用函数的元素对象的(即上述的this指向)
//这里相当于是 调用了debounce函数 然后将运行结果传入 作为参数//此时addEventListener 事件 与debounce函数的执行 没有必然联系 // 所以很多时候会出现 设定的事件还没有触发 就已经将函数debounce中的代码执行了 //函数内this的指向也将继续指向全局的 window ① box.addEventListener('mousemove', debounce(move, 300)) //直接将debounce函数作为参数传入 ② box.addEventListener('mousemove', debounce) // <---相当于---> ③ box.addEventListener('mousemove',function debounce(){ console.log(this) //box })
①写法并不适用于传参 当然可以直接使用 ③写法进行参数传递 但是debounce作为可复用的封装函数 明显也是不合适的
很简单的一种解决方案 ---闭包
box.addEventListener('mousemove', debounce(move, 300)) function debounce(move, 300){ //因为上述事件监听使用的是执行debounce 的返回结果 //所以只要将所有需要的内容 封装到一个函数 就会作为参数返回给addEventListener中 return function(){ //再尝试在这里调用this consoloe.log(this) //box } }
这样子想要的效果就达成了-------
<style> #box{ width: 100%; height: 300px; font-size: 35px; line-height: 300px; text-align: center; background-color: aqua; } </style><div id="box"> </div>
var box = document.querySelector('#box');let count = 0;box.addEventListener('mousemove', debounce(move, 300,true))function debounce(fun, delay, immediate) { // !!!! timeout一定要定义在回调函数外面 let timeout; return function () { let context = this; let args = arguments; clearTimeout(timeout) if (immediate) { let callNow = !timeout; timeout = setTimeout(() => { timeout = null; }, delay); if (callNow) fun.apply(context, args); } else { timeout = setTimeout(function () { fun.apply(context,args) }, delay); } } }function move(e){ box.innerHTML = count++;}
var box = document.querySelector('#box');let count = 0;function move(e) { // 修改前 this 指向 window // console.log(this); //修改了fun的this指向后 这里的 this 已经指向 box 对象 // console.log(this); //修改前 e的值为undefind // console.log(e); box.innerHTML = count++;}//移动鼠标时会不断的执行move函数// box.addEventListener('mousemove',move)// 自定义防抖函数box.addEventListener('mousemove', debounce(move, 1000,true))// box.addEventListener('mousemove', debounce)// box.onmousemove = debounce(move, 300);//underscore防抖函数// box.addEventListener('mousemove',_.debounce(move,300)) // fun 需要进行防抖的函数 delay 延迟的时间 immediate是否立即指向 (true/false)function debounce(fun, delay, immediate) { // console.log(immediate); // immediate为true时会忽略delay的延迟事件 // !!!! timeout一定要定义在回调函数外面 let timeout; // console.log(this); // addEventListener接受的第二个参数为函数 所以必须返回一个函数 (形成了闭包) return function () { // console.log(this); let context = this; //arguments中包含了 事件对象 // console.log(arguments); let args = arguments; // console.log(args); // 函数 fun 在延迟 delay 毫秒后执行 clearTimeout(timeout); //清除计时对象 //判断是否立即执行 if (immediate) { // console.log(timeout); //鼠标移动的瞬间 timeout的值为undefined let callNow = !timeout; //callNow会在移动的一瞬间变为 true // console.log(callNow); timeout = setTimeout(() => { //将延时器变量置空 timeout = null; }, delay) // console.log(timeout); // 立即执行 if (callNow) fun.apply(context, args); } else { //不会立即执行 timeout = setTimeout(function () { // console.log(args); //执行fun函数 改变fun执行上下文this的指向 fun.apply(context,args) //第一个参数 改变fun函数this指向 第二个参数 函数所需要的参数(数组类型) // fun(); }, delay); } }}
欢迎一起交流