node.js 中顶层 this 指向 module.exports 而非 global,这是 commonjs 模块封装机制的必然设计:每个文件被包裹在函数中执行,this 默认绑定为 module.exports,确保模块隔离与导出一致性,而非 bug。

Node.js 中顶层 this 指向 module.exports 而非 global,这不是 bug,而是模块系统设计的必然结果——它源于 CommonJS 规范对“模块封装性”的根本要求。
CommonJS 模块机制决定了 this 的落点
Node.js 早期采用 CommonJS 作为模块标准,每个 .js 文件被包裹在一个函数中执行(类似 (function(exports, require, module, __filename, __dirname) { ... })),顶层代码实际运行在该函数作用域内。此时:
-
this在函数体内默认绑定为该函数被调用时传入的module.exports(即exports的初始值) - 这等价于模块加载器用
module.exports作为this显式调用模块函数:fn.call(module.exports, ...) - 因此
console.log(this === module.exports)恒为true,而this === global为false
与浏览器全局环境的本质区别
浏览器没有模块封装层,全局脚本直接在全局对象(window)上下文中执行,所以 this 默认就是 window。Node.js 则强制所有文件都是模块:
- 即使写的是“全局”变量
var x = 1,它也只在当前模块作用域有效,不会污染global - 若真想挂到全局对象上,必须显式写
global.x = 1或globalThis.x = 1 - 这种隔离是 Node.js 支持多模块共存、避免命名冲突的基础机制
为什么不是 global?历史兼容与安全考量
若让顶层 this 指向 global,会导致严重问题:
- 模块内
this.x = 1就等于global.x = 1,破坏模块封闭性 - 第三方库可能意外覆盖全局属性,引发不可预测的副作用
- CommonJS 规范明确要求模块导出接口统一通过
exports或module.exports,this作为其别名更符合语义一致性
ESM 的对比印证了设计意图
后来引入的 ESM(import/export)彻底切断顶层 this 的可访问性:this 在 ESM 顶层恒为 undefined。这并非推翻旧设计,而是进一步强化模块边界:
- CommonJS 用
this === module.exports提供便捷导出入口 - ESM 用
this === undefined彻底禁止依赖this导出,强制使用export语法 - 两者都服务于同一目标:模块不应隐式污染或依赖全局状态











