import 是编译期静态绑定,解析阶段建立符号到内存地址的只读映射,不执行代码、不创建变量、不触发模块运行;模块加载顺序为解析→实例化→执行,导入绑定在实例化后才就绪,受 TDZ 约束,且路径、语法等均需满足严格静态性要求。

ES Module 执行上下文中的 import 声明不是运行时语句,而是在解析阶段就完成绑定的静态指令——它不执行代码、不创建变量、不触发模块运行,只建立符号到内存地址的只读映射。
import 是编译期静态绑定,不是运行时赋值
引擎在解析模块源码时,就扫描所有顶层 import 语句,确定依赖路径和导入标识符,并构建模块记录(Module Record)。此时模块尚未执行,export 的值也未计算,但导入绑定已确立。
- 例如
import { count } from './counter.js',在counter.js还没运行前,count就已绑定到其未来将持有的内存位置 - 这种绑定是“实时反射”的:一旦
counter.js中count被修改,所有导入它的模块立刻看到新值 - 不能用
let count = ...覆盖导入名,会报SyntaxError或TypeError(严格模式下)
import 声明具有提升(hoisting),但受 TDZ 约束
import 声明会被提升至模块作用域顶部,优先于任何语句执行。但它不等于“可访问”——导入绑定本身处于暂时性死区(TDZ),直到模块实例化完成。
- 模块加载流程为:解析 → 实例化(分配内存、建立绑定) → 执行(填充值)
- 在实例化完成前访问导入绑定,如
console.log(utils)出现在import * as utils from './utils.js'上方,会报ReferenceError - 这与
var提升不同:后者初始化为undefined;而import绑定在就绪前不可触达
import 不引入新作用域,也不污染全局
导入声明只是在当前模块词法环境中添加只读绑定,不创建作用域、不执行模块代码、不挂载到 window 或 globalThis。
-
import * as api from './api.js'中的api是一个普通对象,属性对应命名导出,api.default对应默认导出(若存在) - 该对象是只读的:尝试
api.xxx = null在严格模式下抛错,非严格模式静默失败 - 模块内
this为undefined,与全局上下文的this === window彻底隔离
路径与语法有硬性静态限制
所有 import 语句必须满足静态性要求,这是 ESM 区别于 CommonJS 的核心设计约束。
- 路径必须是字符串字面量:
import { a } from './a.js'✅;import { a } from path❌ - 不能出现在块级作用域中:
if (x) { import { a } from './a.js' }直接语法错误 - 不能解构导入:
import * as { foo } from './m.js'语法非法 - 文件后缀不能省略:
import m from './m'在原生 ESM 中无效,必须写'./m.js'

















