ES6模块天然具备独立作用域,每个文件作为模块加载时自动隔离于全局和其他模块;顶层声明的变量、函数等默认私有,仅通过export显式暴露的接口才可被导入使用。

ES6 模块(ESM)天然具备独立作用域,不需要额外封装。每个 .js 文件只要被当作模块加载(比如通过 <script type="module"> 或 import),它的顶层代码就自动运行在自己的私有作用域中,与全局作用域和其他模块完全隔离。
模块顶层就是独立作用域
在 ESM 中,文件即模块,模块即作用域。你写在模块最外层的 let、const、function、class 等声明,都只在该模块内可见,不会挂到 window(浏览器)或 globalThis 上,也不会被其他模块直接访问。
- 不加
export的变量:纯私有,连同模块内的函数都无法从外部触达 - 加了
export的内容:只是“暴露接口”,不是把变量搬出去,而是建立绑定引用 - 即使两个模块都声明了
const name = 'A',它们互不影响,因为根本不在同一个作用域
和 CommonJS 作用域的关键区别
CommonJS 也提供模块作用域,但机制不同:
- CommonJS 每个文件被包裹在一个函数里(类似 IIFE),靠函数作用域实现隔离
- ESM 是语言级原生支持,没有隐式包装函数,作用域由模块系统本身保障
- ESM 中的
this在顶层为undefined(严格模式强制生效),而 CommonJS 顶层this指向module.exports - ESM 的导入导出是静态声明,在解析阶段就确定关系;CommonJS 的
require是运行时执行,作用域边界虽存在,但依赖时机更动态
实际表现举例
假设有 a.js 和 b.js 两个模块:
立即学习“Java免费学习笔记(深入)”;
// a.jsconst secret = 'shh';export const exposed = 'ok';export function getSecret() { return secret; }
// b.jsimport { exposed, getSecret } from './a.js';console.log(exposed); // 'ok'console.log(getSecret()); // 'shh'console.log(secret); // ReferenceError: secret is not defined
这说明:secret 确实没逃出 a.js 的作用域,外部既不能直接读取,也不能意外覆盖。
注意 script 标签类型的影响
普通 <script> 加载的 JS 是全局作用域;必须显式声明 type="module" 才激活模块作用域:
-
<script src="main.js"></script>→ 全局作用域,变量泄漏风险仍在 -
<script type="module" src="main.js"></script>→ 启用模块作用域,自动严格模式,顶层this为undefined - 哪怕模块内部没有写任何
import或export,只要以模块方式加载,作用域就独立


















