ES6模块的静态结构指import/export语句必须位于顶层、路径为字符串字面量、标识符在解析期确定,使依赖图可在编译时静态分析,支持Tree Shaking等优化,但执行上下文本身仍是运行时动态创建的。

ES6 模块的执行上下文本身并不具备“静态结构”这一属性;真正具有静态特性的,是模块的 语法结构与依赖关系,而非执行上下文。执行上下文(Execution Context)始终是运行时动态创建的,用于管理变量、函数、this 绑定和作用域链——这点在 ES6 和之前版本中完全一致。
模块的静态结构指什么
所谓“静态”,是指模块的 import 和 export 语句必须满足以下硬性约束:
- 只能出现在模块顶层(不能在 if、函数或循环内部)
- 导入路径必须是字符串字面量(如
'./utils.js'),不能是变量或模板字符串 - 导入的标识符名称在代码解析阶段就确定,不可动态计算
- 整个模块依赖图可在构建时(甚至语法分析阶段)被工具完整识别
为什么静态结构不等于执行上下文静态化
执行上下文永远是动态的:每次调用函数、进入模块顶层、执行 eval 都会创建新的上下文并入栈。而模块的静态特性作用于 编译/构建阶段,它让引擎或打包工具能提前知道:
- 哪些导出被实际使用(支持 Tree Shaking)
- 哪些模块存在循环依赖(可提前报错)
- 能否做预加载、代码分割或懒加载规划
也就是说,模块系统把“依赖声明”从运行时搬到了语法层,但模块内部代码的执行,依然严格遵循 JS 的动态执行上下文机制。
静态结构如何影响模块初始化流程
一个 ESM 模块的加载与执行分两步,且顺序严格:
- 实例化(Instantiation):根据 import 声明,为所有导入绑定预留位置,建立模块记录(Module Record),此时不执行任何代码
- 求值(Evaluation):按拓扑序(依赖最浅优先)执行各模块顶层代码,此时才真正创建执行上下文、初始化变量、调用函数
这个两阶段过程依赖静态 import 结构才能可靠排序,但每个阶段内仍由标准执行上下文承载。
对比 CommonJS 更容易看清区别
CommonJS 的 require() 是运行时调用,意味着:
- 依赖路径可以是变量拼接,无法静态分析
- 模块执行时机由 require 出现位置决定,可能嵌套在条件分支里
- 执行上下文与模块加载强耦合,没有分离的实例化阶段
ES6 模块通过静态声明解耦了“声明依赖”和“执行代码”,但并未改变执行上下文本身的动态本质。


















