理解 CommonJS 和 ES Modules 在 JavaScript 中的应用

281 阅读2分钟

CommonJS 和 ES Modules (ESM) 是两种不同的 JavaScript 模块系统。它们在 Node.js 环境中被广泛使用,尽管 ES Modules 也适用于浏览器环境。

CommonJS (CJS)

CommonJS 是为服务器端 JavaScript 开发设计的一种模块化标准,它最早被 Node.js 采用,并成为其默认的模块系统。CommonJS 规定了如何编写模块化的 JavaScript 代码以及如何加载这些模块。

  • 特点:
    • 使用 require 函数来导入其他模块中的变量、函数或对象。
    • 使用 module.exportsexports 对象导出模块中的内容。
    • 在运行时解析依赖,这意味着你可以动态地决定要加载哪个模块。
    • 每个模块都被封装在一个函数作用域内,避免全局变量污染。

代码示例——exports导出

function add (a, b) {
    return a + b
}

exports.hello = 'world';
exports.add = add;
const Add = require('./lib.js')

console.log(Add.add(1, 2), Add.hello); // 输出:3 world

代码示例——module.exports导出

function add (a, b) {
    return a + b
}

module.exports = {
    add: add,
    hello: 'world'
}
const Add = require('./lib.js')

console.log(Add.add(1, 2), Add.hello); // 输出:3 world

ES Modules (ESM)

ES Modules 是 ECMAScript 标准的一部分,定义了 JavaScript 中模块的标准语法。从 ES6 (ES2015) 开始,JavaScript 引入了原生的模块支持。

  • 特点:
    • 使用 importexport 关键字来导入和导出模块内容。
    • 静态解析依赖,在编译时就已经确定了所有依赖关系。
    • 支持树摇(Tree shaking),可以更高效地打包和加载只使用到的部分模块内容。
    • 可以在浏览器和 Node.js 中使用。

代码示例

export function add (a, b) {
    return a + b
}

export const world = 'world';

export default  'world'
import {add, world} from './lib.js'

console.log(add(1, 2), world); // 输出:3 world

对比

  • 互操作性: 在早期版本的 Node.js 中,只能使用 CommonJS。随着 Node.js 版本的发展,现在可以同时支持 CJS 和 ESM。但两者之间存在一些差异,例如处理循环引用的方式不同。
  • 语法差异: CJS 使用 requiremodule.exports,而 ESM 使用 importexport
  • 加载时机: CJS 是运行时加载,而 ESM 是静态解析,这使得 ESM 更适合现代构建工具和优化。

在 Node.js 中使用

Node.js 从 v12.0.0 开始支持 ES Modules。为了使用 ESM,你需要确保文件扩展名为 .mjs 或在 package.json 文件中设置 "type": "module"。对于 CommonJS,则使用 .js 扩展名并保持 "type": "commonjs" 或不指定类型。

总结

总而言之,CommonJS 和 ES Modules (ESM) 是 JavaScript 中两种不同的模块系统,各自拥有独特的特性和应用场景。CommonJS 主要针对服务器端开发,提供了动态加载的能力,并且是 Node.js 中默认的模块系统。另一方面,ES Modules 提供了静态解析依赖的能力,支持树摇等现代构建工具优化技术,并且既适用于浏览器环境也适用于 Node.js 环境。无论是在 Node.js 环境还是浏览器环境中,合理选择和使用模块系统都能帮助我们构建更加健壮、可维护的 JavaScript 应用程序。