💡 写在前面
闭包,这个老生常谈的JavaScript核心概念,是每个前端工程师的必经之路。它看似简单,却在面试中让无数英雄折腰。今天,我们不聊干巴巴的理论,直接上一道“有毒”的代码题。据说,只有10%的人能一次完全答对!
你敢来挑战吗?
🚀 挑战开始:神奇的“计数器工厂”
假设我们有一个“计数器工厂”函数,它应该能生成多个独立的计数器。请看下面的代码: `
第一问(基础题):请问上述五个 console.log 的输出分别是什么?
思考10秒钟...
答案: 6,6,6,6,6 恭喜你,如果答对了!但这只是热身。
🔥 灵魂拷问升级版
现在,我们稍微修改一下代码,情况就变得复杂了:
第二问(进阶题)聪明的你能想到正确答案吗
💎 原理深度解析
第一问的解析:为什么是 五个6?
var声明的变量具有 函数作用域 ,而不是块级作用域。这意味着整个for循环中只有一个i变量实例。循环结束后i的值变为6: 当i=5时,条件i<=5满足,执行完循环体后,i自增为6,然后条件不满足,循环结束。此时i的值是6。
**第二问的解析:为什么是1,2,3,4,5
本来正常的函数代码执行完毕后就会被销毁的,当函数是嵌套函数时当调用一个外部函数中返回的内部函数后,即使外部函数执行结束,但是内部函数依然引用了外部函数的变量,那么外部函数的执行上下文就不能完全销毁,而是会保留一个集合,用来装内部函数需要引用的变量,如图
所以此时V8在当前作用域中查找一个变量,如果找不到,就会去上一级作用域中查找,而outer指针来记录该作用域的外层作用域是谁,此时的上一级作用域就是图中所示的闭包。
🎯 总结与启示
1.一个函数执行完毕后,它的执行上下文会从调用栈中被销毁
2.一个函数的内部函数一定有权力访问该外部函数的变量(作用域)
当调用一个外部函数中返回的内部函数后,即使外部函数执行结束,但是内部函数依然引用了外部函数的变量,那么外部函数的执行上下文就不能完全销毁,而是会保留一个集合,用来装内部函数需要引用的变量,我们把集合称之为闭包。
真正理解闭包,不仅能让你在面试中游刃有余,更能让你在开发中避免无数稀奇古怪的Bug(比如循环中绑定事件)。你,学废了吗?