厘清《You-Dont-Know-JS》中Lexical Scope的定义时机
疑问澄清:两次调用输出差异和词法作用域规则无关
首先明确:你给出的两个案例完全符合《You-Dont-Know-JS》中对词法作用域的定义,不存在矛盾冲突。
无论函数从何处被调用,甚至无论它的调用方式是什么,其Lexical Scope仅由函数的声明位置决定。
这个规则的核心是变量的查找路径在函数声明时就固定,而非路径上对应变量的初始化状态、实时值在声明时就锁定。
第一个示例的逻辑验证
test函数声明在全局作用域下,它的变量查找路径永久固定为:test自身作用域 → 全局作用域,不会受调用位置影响去查找newZone函数的内部作用域,所以调用test永远输出全局的a="1",完全符合词法作用域规则。
第二个示例的差异本质
两次调用test的输出差异,完全是let声明的**暂时性死区(TDZ)**特性导致的,和作用域的确定时机没有关系:
- 两次调用test时,变量查找路径完全一致:先找test内部有没有a、b,找不到就去全局作用域查找,这个路径从test声明完成的那一刻就固定了,从未发生变化。
- 用
let声明的变量存在暂时性死区:从代码进入变量所在作用域开始,到执行完let 变量名 = 赋值语句之前,访问该变量都会抛出引用错误。
第一次调用test时,代码还未执行到let b = 10语句,全局作用域里的b还处于死区,访问直接报错;第二次调用test时,b已经完成初始化,所以能正常输出10。
我们可以加一段代码反证词法作用域规则依旧生效:
let a = 1; function test() { console.log(a, b); } let b = 10; function newZone() { let b = 20; test(); } newZone(); // 输出为1 10,不会读取newZone内部的b=20
可见test永远只会查找全局作用域下的b,完全符合词法作用域的定义。
最终结论
词法作用域确定的是变量的查找路径,不是路径上对应变量的实时状态。你遇到的输出差异只是全局作用域下b的初始化状态变化导致的,和词法作用域的确定时机没有冲突。
内容的提问来源于stack exchange,提问作者turok 9661
相关产品推荐
相关产品推荐

