ES Module 的静态分析发生在解析(Parse)阶段,早于实例化和求值;它仅扫描顶层 import/export 语法,构建依赖图、预留绑定地址,不执行代码、不检查路径,确保编译期可判定。

ES Module 的执行上下文不是靠运行时推断,而是在代码解析阶段就由 JavaScript 引擎完成静态分析。这个过程不执行任何语句,只读取 import/export 语法结构,从而提前建立模块依赖图、绑定导出变量地址、识别循环依赖,并为后续实例化和求值打下基础。
静态分析发生在哪个环节
它属于模块处理的**解析(Parse)阶段**,早于实例化(Instantiation)和求值(Evaluation)。引擎扫描源码时,只要遇到顶层的 import 或 export,就立即记录模块关系,不关心变量是否已声明、函数是否被调用,甚至不检查路径是否存在——这些是加载器(loader)或运行时的事。
- import 语句被提取为“模块说明符”,用于构建模块图(Module Graph)
- export 语句被收集为“导出绑定列表”,每个导出名都关联一个内存位置(binding),但此时尚未赋值
- 所有 import 都被提升到模块顶部统一处理,等效于“声明提前”,但不同于 var 提升——它不初始化值,只预留引用
为什么必须是顶层且不能条件化
因为静态分析无法执行代码逻辑。if、try、函数作用域、变量拼接等都会让 import/export 的存在与否依赖运行时状态,破坏“编译期可判定”这一前提。
- 合法:import { a } from './x.js'; export const b = 1;
- 非法(语法错误):if (flag) { import { a } from './x.js'; } 或 const mod = './' + name; import x from mod;
- 动态导入 import('./x.js') 是特例——它返回 Promise,由引擎在运行时按需解析,不参与初始静态图构建
静态分析如何支撑模块执行
它直接决定了模块环境记录(Module Environment Record)的结构,这是 ES Module 执行上下文的核心载体。
- 每个模块对应一个独立的词法环境,其变量对象(Variable Object)由静态导出绑定预先定义
- import 绑定与 export 绑定指向同一内存地址(live binding),修改导出值会实时反映在所有导入处
- 循环依赖能被检测并安全处理:静态分析可发现 A→B→A 路径,在实例化阶段为未就绪的导出设置临时占位,避免报错
和 CommonJS 执行上下文的关键区别
CommonJS 每个模块被包装成函数:(function(exports, require, module, __filename, __dirname) { ... }),执行时才动态计算依赖、生成 exports 对象;而 ESM 的执行上下文从解析开始就固化了模块边界与绑定关系。
- CommonJS 的 require() 是运行时调用,可写在任意位置,结果取决于当前执行流
- ESM 的 import 是声明式元信息,与执行流解耦,支持 Tree Shaking、跨工具链优化、类型推导等
- ESM 自动启用严格模式,无 var 声明提升,无 arguments/caller,执行上下文更纯净

















