JS事件监听代码中点击按钮count为何逐次递增?闭包如何生效?
闭包形成逻辑与示例代码运行原理解答
你给出的示例代码如下:
function attachEventListeners() { let count = 0 document.getElementById("clickMe").addEventListener("click", function () { console.log("Button Clicked", ++count) }) } attachEventListeners()
你对闭包的认知存在一个小偏差:闭包生效的核心条件是内部函数被外部作用域持有引用、且内部函数访问了外层函数的变量,并不是必须要通过return将内部函数返回并赋值给变量才可以。
这段代码的运行和闭包形成过程如下:
- 调用
attachEventListeners时,函数作用域内会创建初始值为0的局部变量count - 执行
addEventListener方法时,作为参数传入的匿名点击回调函数,会被浏览器的事件管理系统持有引用,不会随着attachEventListeners执行结束而被销毁 - 这个匿名回调函数访问了外层作用域的
count变量,因此形成闭包:attachEventListeners执行完成后,原本应该被回收的函数作用域因为回调函数的引用被保留,count变量也随之留存,不会被重新初始化 - 后续每次触发按钮点击事件时,执行的都是同一个回调函数,访问的都是同一个被留存的
count变量,因此可以实现逐次递增的效果
你之前认知里的「返回内部函数赋值给变量」只是闭包的常见使用场景之一,和当前示例的本质逻辑完全一致:都是内部函数逃出了外层函数的作用域范围,被外部其他模块持有引用,从而让外层函数的局部变量可以跨越作用域生命周期被持续访问。
如果多次调用attachEventListeners,每次调用都会生成独立的count变量和独立的事件回调,点击按钮时会按照绑定顺序触发多个回调,每个回调只累加自己绑定的count值。
内容的提问来源于stack exchange,提问作者anandsr-dev
相关产品推荐
相关产品推荐

