关于JavaScript中setTimeout内Lexical Scoping的疑问
理清JavaScript词法作用域与闭包的困惑
嘿,我来帮你把这个困惑理清楚——其实这两个例子刚好完美展现了JavaScript词法作用域加上闭包的核心特性,完全不矛盾哦!
先明确词法作用域的核心规则:函数的作用域是在它被定义的时候就确定的,而不是在调用的时候。接下来咱们逐个分析你的例子:
示例1:Test函数无法访问Main内的bar
//Example No 1 without using setTimeout() function Main() { var bar = "Main"; Test(); } function Test() { console.log(bar); } //Prints bar is undefined which is fine as it is Lexical Scoping and bar is //fine as there is no bar variable in Test() or Global Context Main()
你看到的报错完全符合词法作用域的规则:Test函数是在全局作用域下定义的,它的词法环境只包含自身作用域和全局作用域。Main函数里的bar是Main的局部变量,属于Main的私有作用域,Test定义的时候根本不在这个作用域里,所以它找不到这个bar,自然会报错“bar未定义”。
示例2:setTimeout回调能访问main内的bar
//Example 2 with setTimeout() var bar = "outside"; function main() { var bar = "Main"; setTimeout(function() { console.log(bar); }, 1000) } //Prints value of bar = "Main" main();
这个例子的关键在于闭包:setTimeout的回调函数是在main函数内部定义的,所以它的词法环境包含了main函数的作用域。哪怕1秒后回调才执行,这时候main函数已经执行完毕,但闭包会让回调函数保留对main作用域的引用,所以它能访问到main里的bar,而不是全局的"outside"。这完全符合词法作用域的规则——因为回调定义在main内部,所以它天生就有权访问main的局部变量。
简单总结一下:
- 函数能访问哪些变量,看的是它被定义的位置,不是被调用的位置
- 示例1的Test定义在全局,只能访问全局和自身作用域的变量
- 示例2的回调定义在main内部,借助闭包就能一直持有对main作用域的访问权,哪怕main已经执行完
内容的提问来源于stack exchange,提问作者user3045179
相关产品推荐
相关产品推荐

