模块顶层this为undefined是规范强制设定:因es模块默认严格模式、拥有独立模块环境、不共享全局上下文,且为杜绝隐式全局污染,故禁止this绑定全局对象。

模块内顶层 this 是 undefined,不是出错了,而是模块作用域和全局作用域在设计上就彼此隔离——模块不继承全局执行上下文,也不参与全局对象的隐式绑定。
模块作用域天然独立于全局作用域
每个 ES 模块(.mjs 文件或 <script type="module"></script>)都会被解析为一个独立的模块记录(Module Record),它拥有专属的模块环境(Module Environment)。这个环境不共享浏览器的 window 或 Node.js 的 globalThis,所有 let、const、function 声明都绑定在模块环境里,而非全局环境。
- 模块顶层没有“调用者”,所以
this没有隐式绑定目标 - 模块不是函数,不适用“函数调用时
this如何绑定”的规则 - 模块作用域与全局作用域是平行关系,不是嵌套关系
严格模式强制 this 为 undefined
ES 模块默认启用严格模式(无需写 "use strict")。根据 ECMAScript 规范(ECMA-262 §10.2.1),严格模式下,全局作用域中的 this 不再自动绑定到全局对象,而是统一设为 undefined。
- 非模块脚本中
this === window(浏览器)或globalThis(Node.js) - 模块脚本中,哪怕只有一行
console.log(this),输出也是undefined - 这是语言级标准化行为,所有现代引擎(V8、SpiderMonkey、JavaScriptCore)均一致实现
模块设计拒绝隐式全局污染
如果模块顶层 this 指向 window,那么 this.api = fetch 就会悄悄往全局挂属性,破坏封装性。规范主动让 this 为 undefined,相当于关掉了这条隐式通道。
- 想访问全局对象?必须显式写
globalThis - 想暴露功能给其他模块?走
export/import - 想共享状态?通过导出对象或单例模块,而不是依赖
this
和 CommonJS 的 this 完全不是一回事
CommonJS 中模块顶层 this === module.exports,是因为每个文件被包裹在函数里:function (exports, require, module) { ... }。而 ES 模块不包装函数,也没有“模块上下文对象”作为 this 的默认值。
- CommonJS 的
this是运行时注入的导出载体 - ES 模块的
this是词法环境的逻辑结果,无载体可绑 - 二者模型不同,不能类比理解











