在现代的
JavaScript
开发中,模块化是一个至关重要的概念,它有助于将代码拆分为独立的、可维护的部分,使开发过程更加高效和可靠。在JavaScript
社区中,有两种主要的模块化规范:CommonJS
(通用模块化规范)和ESM
(ECMAScript
模块)规范。本文将深入探讨这两种规范的异同点、应用场景以及注意事项。
CommonJS
是一种早期引入的模块化规范,最初用于服务器端JavaScript
(如Nodejs
)。它的主要特点包括:
CommonJS
模块是同步加载的,即在需要的地方使用require
函数加载模块,并立即获取其导出内容。module.exports
导出模块内容,或者通过给exports
对象添加属性来导出单个成员js// 导出
// utils.js
module.exports = {
add: (a, b) => a + b,
subtract: (a, b) => a - b
};
// 导入
// app.js
const { add, subtract } = require('./utils');
console.log(add(5, 3)); // 输出: 8
console.log(subtract(5, 3)); // 输出: 2
js// 导出
// utils.js
exports.add = (a, b) => a + b;
exports.subtract = (a, b) => a - b;
// 导入
// app.js
const { add, subtract } = require('./utils');
console.log(add(5, 3)); // 输出: 8
console.log(subtract(5, 3)); // 输出: 2
js// 导出
// utils.js
module.exports = (a, b) => a + b;
// 导入
// app.js
const add = require('./utils');
console.log(add(5, 3)); // 输出: 8
ESM
是ECMAScript
官方引入的模块化规范,它在现代浏览器和Nodejs
中都得到了广泛支持。它的主要特点包括:
ESM
模块是异步加载的,模块需要使用import
语句加载,可以在运行时动态加载模块。export
关键字导出模块内容,可以导出多个成员,也可以起别名。使用export
关键字,可以命名导出一个或多个成员,这些成员在导入时需要使用相应的名称来访问。
js// 导出
// utils.js
export function add(a, b) {
return a + b;
}
export function subtract(a, b) {
return a - b;
}
// 导入
// app.js
import { add, subtract } from './utils';
console.log(add(5, 3)); // 输出: 8
console.log(subtract(5, 3)); // 输出: 2
使用export default
关键字,可以导出一个默认成员,一个模块只能有一个默认导出。
js// 导出
// utils.js
const add = (a, b) => a + b;
export default add;
// 导入
import add from './utils';
console.log(add(5, 3)); // 输出: 8
在导入时,可以自定义默认导出成员的名称:
js// 导入并重命名
import myAddFunction from './utils';
console.log(myAddFunction(5, 3)); // 输出: 8
在一个模块中,既可以有命名导出,又可以有默认导出。
js// 导出
// utils.js
export function add(a, b) {
return a + b;
}
function subtract(a, b) {
return a - b;
}
export default subtract;
// 导入
// app.js
import subtract, { add } from './utils';
console.log(add(5, 3)); // 输出: 8
console.log(subtract(5, 3)); // 输出: 2
可以在一个模块中重新导出另一个模块的成员,方便从一个中心模块导出所有需要的内容。
js// 导出一
// mathUtils.js
export function add(a, b) {
return a + b;
}
// 导出二
// utils.js
export function subtract(a, b) {
return a - b;
}
export function multiply(a, b) {
return a * b;
}
// 引入后重新集中导出
// main.js
export { add } from './mathUtils';
export { subtract, multiply } from './utils';
// 导入
// app.js
import { add, subtract, multiply } from './main';
console.log(add(5, 3)); // 输出: 8
console.log(subtract(5, 3)); // 输出: 2
console.log(multiply(5, 3)); // 输出: 15
使用import * as <alias>
语法,可以将一个模块的所有导出成员导入为一个对象。
js// 导出
// utils.js
export function add(a, b) {
return a + b;
}
export function subtract(a, b) {
return a - b;
}
// 导入
// app.js
import * as math from './utils';
console.log(math.add(5, 3)); // 输出: 8
console.log(math.subtract(5, 3)); // 输出: 2
这些是ESM
规范中常见的导出方式,通过灵活运用它们,可以更好地组织和管理模块化的JavaScript
代码。
CommonJS
使用同步加载模块,适合服务器端,但在浏览器中可能会造成阻塞。ESM
使用异步加载模块,更适合浏览器环境,可以提高性能。ESM
可以在静态分析时确定模块依赖关系,这使得一些优化和工具更易实现。CommonJS
在运行时才能确定依赖,限制了某些优化的可能性。ESM
允许使用import()
函数在运行时动态加载模块,以支持按需加载。CommonJS
没有原生的动态导入方式,尽管在Nodejs
中可以使用实验性的import()
函数。CommonJS
适用于服务器端应用,特别是在Nodejs
环境中,可以方便地管理模块依赖。ESM
适用于浏览器和现代Nodejs
应用,尤其在前端项目中,可以利用浏览器的异步加载能力Nodejs
中使用ESM
规范时,需要在脚本文件中使用.mjs
扩展名,并在package.json
中设置"type"
: "module"
。ESM
中的模块路径解析相对于当前文件,而CommonJS
中相对于包含模块的目录。ESM
中的导入和导出是静态的,不能根据条件进行导入或导出,而CommonJS
可以在运行时根据条件加载模块。CommonJS
和ESM
规范各有优势,选择取决于应用的环境和需求。
在Nodejs
环境中,可以根据项目需求选择使用哪种规范,而在现代的浏览器环境中,ESM
规范更加适用。
熟悉这两种规范的异同以及各自的应用场景,将有助于开发者更好地进行模块化开发并提高代码质量和可维护性。
本文作者:CreatorRay
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!