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

全局作用域下同一变量为何可搭配window.a与let声明,却不能同时用var和let声明

核心原因:ES规范对全局作用域的词法环境做了分层设计

1. 全局作用域的两层环境记录

全局执行上下文的词法环境分为两个独立的存储区域,对应你提到的两种内存划分:

  • 对象式环境记录:也就是所说的「全局内存」,绑定到浏览器宿主的全局对象window,所有var声明、顶层函数声明都会存在这里,直接给window加属性也等价于在这层新增绑定。
  • 声明式环境记录:也就是所说的「脚本内存」,是ES6新增的存储区域,专门用来存let、const、class等块级声明的绑定,不会挂载到window对象上。

标识符查找时会优先匹配声明式环境记录的内容,匹配不到才会继续查找对象式环境记录的内容。


2. 第一段代码运行正常的原因

// At global scope
window.a = 42;    // Creates binding in the outer global environment
let a = "answer"; // Creates binding in the inner global environment
console.log(a);   // Shows "answer"
  • window.a = 42只是给window对象新增了一个普通属性,仅在对象式环境记录里新增了a的绑定,不会在全局作用域的「已声明标识符校验池」里注册这个变量名。
  • let a = "answer"是在声明式环境记录里新增绑定,两层存储区域相互独立,不存在命名冲突,所以运行正常。
  • 打印时优先取声明式环境记录的a,因此输出answer,如果要获取42的取值可以手动访问window.a。

3. 第二段代码抛重复声明错误的原因

// At global scope
var a = 42;    
let a = "answer"; 
  • var a = 42除了会在对象式环境记录里新增window.a的绑定,还会把a这个名字注册到全局作用域的「已声明标识符校验池」里,标记为已经被声明过的变量。
  • let声明变量前会强制校验当前作用域的校验池,只要存在同名的已注册变量(不管是var声明的还是其他let/const声明的),就会直接抛出SyntaxError: Identifier 'a' has already been declared的语法错误,和变量实际存储在哪层环境记录没有关系。

内容的提问来源于stack exchange,提问作者srrsre

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 13:06:01