V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
WNW
V2EX  ›  程序员

JavaScript 防抖函数,绑定事件后事件对象传参问题

  •  
  •   WNW · 2022-09-12 14:48:29 +08:00 · 2278 次点击
    这是一个创建于 806 天前的主题,其中的信息可能已经有所发展或是发生改变。

    明明事件对象 e 是作为的 debounce 中的第一个 fn 函数参数,为什么能够被 debounce 函数返回的匿名函数中 的...args 获取得到呢?实在想不通,不知道有哪位同学可以答疑解惑,不胜感激

    // 防抖
    function debounce(func, wait = 500) {
    
      let timeID;
    
      return function (...args) {
    
        if (timeID) clearTimeout(timeID);
        timeID = setTimeout(() => {
          func.apply(this, args);
        }, wait);
        
      }
    
    }
    
    let password = document.querySelector('[name="password"]');
    
    
    // 明明事件对象 e 是作为的 debounce 中的第一个 fn 函数参数,为什么能够被 debounce 函数返回的匿名函数中
    // 的...args 获取得到呢?实在想不通,不知道有哪位同学可以答疑解惑,不胜感激
    
    password.addEventListener("keyup", debounce(function (e) { 
    	console.log(222) 
    }, 500));
    
    
    
    
    
    17 条回复    2022-09-13 14:30:37 +08:00
    zjffun
        1
    zjffun  
       2022-09-12 15:20:45 +08:00
    debounce 返回的是一个函数,可以先分析这个更简单的流程看看

    ```js
    function debounce(func) {
    return function (...args) {
    console.log("args", args);
    func(...args);
    };
    }

    let password = document.querySelector('[name="password"]');

    const debouncedFn = debounce(function (e) {
    console.log(222);
    });

    console.log("debouncedFn", debouncedFn);

    password.addEventListener("keyup", debouncedFn);
    ```
    zjffun
        2
    zjffun  
       2022-09-12 15:28:51 +08:00
    WNW
        3
    WNW  
    OP
       2022-09-12 15:52:09 +08:00
    @zjffun 好的谢谢,我先试试
    Justin13
        4
    Justin13  
       2022-09-12 17:47:16 +08:00 via Android
    因为你绑定的就是 debounce 的返回值
    dasbn
        5
    dasbn  
       2022-09-12 17:56:58 +08:00
    因为你使用的就是 debounce 函数返回的匿名函数 , 原函数已经被包起来了,func.apply(this, args); 这一句就是调用原来的函数。并不是匿名函数获取对象 e ,而是匿名函数把 e 传递给原来的函数作为参数。
    walking50w
        6
    walking50w  
       2022-09-12 18:02:11 +08:00
    ```
    function debounce(func, wait = 500) {

    let timeID;

    return function fn(...args) {

    if (timeID) clearTimeout(timeID);
    timeID = setTimeout(() => {
    func.apply(this, args);
    }, wait);

    }

    }

    ```
    walking50w
        7
    walking50w  
       2022-09-12 18:08:59 +08:00
    @silasamiseaf94
    // 重新命名, 简化
    debounce(outer, wait = 500) {
    function inner(e) {
    outer.apply(null, e)
    }
    return inner
    }
    // callback 执行顺序
    // 延时后
    onKeyup => inner(e) => outer(e)
    // 所以 outer 中 e 来自 inner
    WNW
        8
    WNW  
    OP
       2022-09-12 20:10:47 +08:00
    @dasbn 问题是匿名函数得先获取才能传递啊,我疑惑的就是匿名函数是怎么获取得到 e 的,获取到了才能再传递
    WNW
        9
    WNW  
    OP
       2022-09-12 20:14:36 +08:00
    @silasamiseaf94 了解明白了
    WNW
        10
    WNW  
    OP
       2022-09-12 20:36:46 +08:00
    @silasamiseaf94 我知道 outer 的 e 来自 inner,问题只 inner 的 e 是从哪儿来的?
    walking50w
        11
    walking50w  
       2022-09-12 21:12:38 +08:00
    @WNW 我的天,debounce 返回的 inner 作为 onKeyup 的回调, 回调触发事件,调用 inner 注入 e 参数
    demonzoo
        12
    demonzoo  
       2022-09-12 21:38:57 +08:00
    说实话没太看懂你的问题点在哪里,单说 args 的话不就是个闭包?
    WNW
        13
    WNW  
    OP
       2022-09-13 09:30:36 +08:00
    @silasamiseaf94 可是 e 明明传给的是 debounce 的第一个 outer 作为 outer 的参数 outer(e),在还没有返回闭包也就是 inner 的时候 e 是随着 outer 先进入 debounce 函数第一层,我的疑惑就是 outer(e)带着 e 进来,这个 e 是怎么被 inner(...args)获取得到的,我知道 inner 里面又从新把 e 通过 apply 再次传递给 outer 了
    WNW
        14
    WNW  
    OP
       2022-09-13 09:41:46 +08:00
    @silasamiseaf94
    password.addEventListener("keyup", debounce(function (e) {
    console.log(222)
    }));
    这里调用的 debounce 的 function(e){} 就是你的 outer,如果按你的理解其实 e 传给的实际上是 inner(...agrs),这个 e 第一步 debounce 执行的时候是直接传给了返回的闭包也就是 inner(...agrs)被...agrs 获取了再传给 outer 了
    walking50w
        15
    walking50w  
       2022-09-13 11:39:36 +08:00
    @WNW addEventListener 的时候,先执行了 debounce() ,实际绑定的是 debounce 执行后返回的函数 inner 。

    addEventListener('keyup', debounce(fn, 500) )
    == let inner = debounce(fn, 500); addEventListener('keyup', inner )
    // 整个流程的顺序是 先执行 debounce()函数,debounce 返回了新的函数 inner , 新的函数作为 keyup 事件的回调函数。
    事件出发后 inner 执行,inner 中再去调用 outer
    DICK23
        16
    DICK23  
       2022-09-13 11:50:05 +08:00
    就是一个占位参数,绑定返回后的函数的参数
    WNW
        17
    WNW  
    OP
       2022-09-13 14:30:37 +08:00
    @silasamiseaf94 明白了,感谢感谢
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3980 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 05:11 · PVG 13:11 · LAX 21:11 · JFK 00:11
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.