You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

厘清《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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 11:45:01