JavaScript中addEventListener回调为何能访问外部作用域btn变量
问题解答
你观察到的现象是JavaScript闭包+词法作用域规则的正常表现,完全符合语言设计逻辑,拆成几个好理解的点说明:
- 首先明确JS最基础的作用域规则:函数的作用域在它被定义的那一刻就固定了,和它最终在哪里被调用没有关系。所有函数都会记住自己被创建时所处的外层作用域里的所有变量,只要这个函数本身还存在、没被垃圾回收,它就能一直访问这些外层变量,哪怕外层的代码早就执行完了。
- 回到你写的代码:
let btn = document.querySelector("button"); btn.addEventListener("click",() => console.log(btn.textContent));
你写的这个箭头回调函数,和btn变量是在同一个作用域下被创建的——你只是把这个函数的引用当参数传给了addEventListener方法,并没有改变这个函数本身的作用域绑定。
- 你之前误以为变量会超出作用域,大概率是觉得回调传给
addEventListener之后,就跑到别的独立上下文里执行了,外层的btn就访问不到了。实际上这个回调被触发执行的时候,依然会沿着自己定义时就确定好的作用域链向上查找变量,自然就能找到同作用域下的btn。
换个更直白的例子你就能立刻懂:
function createFn() { const testVal = "我是外层函数的变量"; // 把内部定义的函数返回出去,传到外层 return function() { console.log(testVal); } } const fn = createFn(); // 这里createFn已经执行完了,按你之前的理解testVal应该被销毁了 fn(); // 执行后依然能正常打印「我是外层函数的变量」,和你代码里btn能被访问是完全一样的原理
这种「函数能记住并访问自己定义时所在作用域的变量,哪怕函数在作用域之外执行」的特性,就是JS里的闭包。你写的事件回调,本质就是一个最常见的闭包使用场景。
内容的提问来源于stack exchange,提问作者Lorenzo Zabot
相关产品推荐
相关产品推荐

