早期的 JavaScript 没有官方模块系统,社区先后出现了 CommonJS(Node.js 采用)和 AMD 等方案,ES6 终于把 ES Module 写进语言标准。现代浏览器和 Node.js 都原生支持 ESM,新项目应当默认使用它。
1. ESM 基本语法
// utils.js:命名导出(一个文件可以多个)
export function add(a, b) { return a + b; }
export const version = "1.0";
// main.js:按名导入
import { add, version } from "./utils.js";
// 默认导出(一个文件只有一个)
export default class Calculator { /* ... */ };
import Calculator from "./calculator.js";
// 全量导入与重命名
import * as utils from "./utils.js";
import { add as plus } from "./utils.js";
2. ESM 与 CommonJS 的核心差异
CommonJS (require) ES Module (import)
加载时机 运行时动态加载 编译期静态分析
导出内容 值的拷贝 值的引用(绑定)
顶层 this 指向当前模块 undefined
循环依赖 可能拿到不完整对象 支持,靠静态结构
按需加载 可以在 if 里 require 必须 import 静态声明(动态用 import())
// CommonJS 的值拷贝问题
// counter.js
let count = 0;
setTimeout(() => { count = 1; }, 100);
module.exports = { count };
// main.js
const { count } = require("./counter.js");
setTimeout(() => { console.log(count); }, 200); // 0!拿到的是旧值
// ESM 是活绑定,读到最新值
3. 动态导入
import() 返回 Promise,适合按需加载和代码分割,打包工具据此做路由级分包:
button.addEventListener("click", async () => {
const module = await import("./heavy-chart.js");
module.render();
});
4. 浏览器中的使用
<script type="module" src="./main.js"></script>
type=”module” 的脚本默认严格模式、自带 defer 行为(不阻塞解析、按文档顺序执行)、路径必须写全(不能省略 ./ 和扩展名,这是和 CommonJS 的习惯差异)。
5. 迁移建议
Node.js 项目在 package.json 加 “type”: “module” 即可整体切换 ESM,或在文件后缀用 .mjs;老项目迁移时优先把「有循环依赖、需要树摇优化」的模块先改掉,收益最明显。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END








暂无评论内容