【JavaScript】模块化:ES Module 与 CommonJS

早期的 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
喜欢就支持一下吧
点赞9 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容