为Word DOM元素绑定keypress事件监听器时Event对象丢失的问题求助
为什么使用bind传递参数后,keypress事件的Event对象变成undefined了?
我想给每个word DOM元素绑定keypress事件监听器,并且把元素本身传递给事件处理函数。我试了下面的代码,但发现Event对象丢失了:
const eventHandler = (e, word) => { console.log('keypressed', String.fromCharCode(e.which), word); } words.forEach((word) => { window.addEventListener("keypress", eventHandler.bind(event, word)); });
原本String.fromCharCode(e.which)应该返回按下的按键,但现在完全没有输出。我写了简化的复现代码,按下任意键会发现event是undefined:
const eventHandler = (event, word) => { console.log('keypressed', event, word); } window.addEventListener("keypress", eventHandler.bind(this, event, 'word'));
请问该怎么修复这个问题?
问题根源
你这里的问题出在Function.prototype.bind()的工作机制上:
bind()的第一个参数是绑定给函数的this上下文,后面的参数是提前注入到函数的前置参数。- 你在
bind(this, event, 'word')里传的event在执行bind的时候根本还没发生,此时它是undefined,所以当事件触发时,浏览器传入的真正Event对象会被排在你预设的参数之后。 - 你的处理函数
eventHandler期望第一个参数是Event对象,但实际第一个参数是你预设的undefined,真正的Event对象变成了第二个参数,自然就拿不到正确的值了。
修复方案
有两种常用的修复方式,你可以根据需求选择:
方法1:调整参数顺序并正确使用bind
把处理函数的参数顺序改成先接收预设的word,再接收Event对象,然后用bind绑定word作为前置参数:
// 调整参数顺序:先word,再event const eventHandler = (word, e) => { console.log('keypressed', String.fromCharCode(e.which), word); } words.forEach((word) => { // bind的第一个参数是this(这里用null/this都可以,因为函数里没用到this),第二个参数是word window.addEventListener("keypress", eventHandler.bind(null, word)); });
这样事件触发时,浏览器传入的Event对象会作为第二个参数进入eventHandler,就能正常获取按键值了。
方法2:用箭头函数包裹(更直观)
用箭头函数作为事件监听器,它可以直接捕获当前循环中的word变量,然后在箭头函数里调用处理函数,手动传入Event对象和word:
const eventHandler = (e, word) => { console.log('keypressed', String.fromCharCode(e.which), word); } words.forEach((word) => { window.addEventListener("keypress", (e) => eventHandler(e, word)); });
这种方式不需要纠结bind的参数顺序,代码可读性更高,也是现在更推荐的写法。
验证简化示例
用方法2修复你的简化代码:
const eventHandler = (event, word) => { console.log('keypressed', event, word); } window.addEventListener("keypress", (e) => eventHandler(e, 'word'));
现在按下按键,就能看到正常的Event对象和word值了。
内容的提问来源于stack exchange,提问作者Sara Ree
相关产品推荐
相关产品推荐

