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

全局作用域下var与let的差异:全局对象属性的实际影响

顶层作用域let/var与全局对象的差异解析

一、实际影响

  • 避免全局对象污染
    用var声明的顶层变量会成为全局对象(浏览器中是window,Node.js中是globalThis)的可枚举属性,容易造成命名冲突。比如:

    var title = "全局标题";
    console.log(window.title); // 输出"全局标题"
    

    而let声明的变量不会挂载到全局对象,不会给全局对象增加额外属性:

    let title = "全局标题";
    console.log(window.title); // 输出undefined
    

    这在多人协作或引入第三方库时,能大幅减少因全局属性重名导致的意外bug。

  • 访问方式的限制
    你无法通过全局对象来访问let声明的顶层变量,比如想动态通过变量名访问时:

    var foo = 1;
    console.log(window["foo"]); // 输出1
    
    let bar = 2;
    console.log(window["bar"]); // 输出undefined
    

    这既是限制也是保护——它避免了通过全局对象意外修改顶层变量的可能,让变量的访问更可控。

  • 对全局对象原有属性的保护
    如果全局对象本身已有某个属性(比如浏览器的window.name),用var声明同名变量会直接覆盖这个属性:

    var name = "张三";
    console.log(window.name); // 输出"张三"(原有的window.name被覆盖)
    

    但let声明的同名变量会在顶层词法环境中创建独立绑定,只会遮蔽全局对象的属性,不会修改它:

    let name = "张三";
    console.log(window.name); // 输出原来的window.name值(比如空字符串或当前页面名称)
    console.log(name); // 输出"张三"
    

二、深层机制与区分的意义

这个区分绝非无意义,它是JS作用域模型进化的关键一步:

  • 旧有机制的遗留问题
    var属于ES3/ES5的函数作用域机制,早期JS没有块级作用域,全局对象被当作顶层作用域的载体,所以var声明的全局变量会挂载到全局对象上。但这种设计很容易导致变量泄漏、意外修改全局属性等问题。
  • ES6的词法环境优化
    ES6引入块级作用域后,顶层的let/const会被存储在顶层词法环境中,而非全局对象的属性。这让JS的作用域模型更接近传统编程语言,减少了“变量提升”“全局污染”这类反直觉的怪异行为。
  • 为模块化铺路
    在ES模块中,顶层的var/let都不会挂载到全局对象,而浏览器普通脚本中let的行为和模块保持一致,这为JS从全局式开发过渡到模块化开发提供了兼容性基础。

三、关于MDN定义的疑问

MDN的定义并没有过时,只是需要结合JS版本语境理解:

  • ES5及以前,全局变量确实等同于全局对象的属性,因为当时只有var和函数声明两种全局变量方式。
  • ES6引入let/const/class后,全局作用域出现了两类变量:
    1. 绑定到全局对象的:var、函数声明的全局变量,以及未声明直接赋值的变量(比如abc = 123)。
    2. 绑定到顶层词法环境的:let、const、class声明的全局变量。
  • 不存在“二等全局变量”的说法,这两类变量都是全局作用域的成员,都能在所有作用域访问,只是存储位置和访问规则不同。而且顶层词法环境的变量优先级更高,会遮蔽全局对象的同名属性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 22:54:59