1. 为什么现在必须学会 ESM
如果只停留在“会写 import 语法”,很容易在工程化项目里踩坑。
ESM 真正重要的点在于:
一句话:ESM 不只是新语法,是现代前端工具链的默认前提。
2. ESM 的核心语法
2.1 导出:具名 + 默认
// named export
export const a = 1;
export function b() {}
// default export
export default function main() {}
要点:
- 具名导出可以有多个
- 默认导出最多一个
- 两者可以同时存在
2.2 导入:四类最常见写法
import './setup.js';
import { a, b } from './mod.js';
import main from './mod.js';
import * as ns from './mod.js';
再补一个动态导入:
const mod = await import('./mod.js');
import() 返回 Promise,适合按需加载。
3. 最容易误解的点:ESM 不是“导出一个普通对象”
很多教程会把模块导出结果画成一个对象,这在教学演示上方便,但容易误导。
更准确的理解:
- 模块对外暴露的是一组“导出绑定”
- import * as ns 拿到的是模块命名空间对象(Module Namespace Object)
- 这不是你自己创建的普通对象字面量
示意:
import * as ns from './mod.js';
console.log(ns.default);
console.log(ns.someNamed);
可以“像对象一样访问”,但语义不是“对象解构 + 值拷贝”。
4. live binding:为什么导入变量不能重新赋值
// counter.js
export let count = 0;
export function inc() {
count++;
}
// main.js
import { count, inc } from './counter.js';
console.log(count); // 0
inc();
console.log(count); // 1
// count = 2; // TypeError
这说明两件事:
这也是 ESM 和“对象解构”在语义上的关键差别。
5. 顶层限制:不是“必须第一行”,而是“必须顶层”
常见说法是“import/export 必须写在文件最上面”,这不严谨。
更准确说法:
- 静态 import / export 必须出现在模块顶层
- 不能放进 if、循环、函数体
- 实践中放顶部是风格约定,不是语法要求“第一行”
6. 浏览器里的 ESM:你要记住的 4 个点
<script type="module" src="./main.js"></script>
7. Node.js 里的 ESM:和浏览器相同但不完全相同
Node.js 里常见启用方式:
在 Node ESM 环境中:
- 没有 require / module.exports
- 没有 __filename / __dirname
- 常用 import.meta.url(新版还有 import.meta.dirname 等)
- 相对导入通常要显式扩展名
示例:
import { readFileSync } from 'node:fs';
const text = readFileSync(new URL('./data.txt', import.meta.url), 'utf8');
8. ESM 和 CommonJS 的互操作:
Node.js 中 ESM 与 CJS 可以互操作,但建议记“最稳策略”:
ESM 导入 CJS,优先默认导入:
import pkg from './legacy.cjs';
因为默认导入通常对应 module.exports。
具名导入 CJS 有时可用,但依赖静态分析推断,跨环境稳定性不如默认导入。
9. CJS vs ESM 速查表
| 导入 | require() | import / import() |
| 导出 | module.exports / exports | export / export default |
| 依赖分析 | 偏运行时 | 天然支持静态分析 |
| 绑定语义 | 常围绕导出对象工作 | live binding |
| 浏览器原生支持 | 不支持 | 支持 |
| 工程化适配 | 需要更多工具兼容 | 更适合现代前端工具链 |
10. 结语
ESM 真正难的不是语法,而是语义和运行时差异。
如果你把这 5 个点吃透,工程化里大部分模块化问题都能快速定位:
参考文档:
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export
- https://nodejs.org/api/esm.html
版权声明:本文为学习整理稿,欢迎交流,转载请注明出处。
