01-addEventListener事件监听的传参调用问题

发布于 2022年 04月 11日 05:58

前端问题小记-01 addEventListener

今天学习手写防抖函数的时候遇到了一个小问题

            //为鼠标移动事件添加防抖函数
        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);
    }
   
    
  }

}

欢迎一起交流

推荐文章