ES模块系统与CommonJS模块系统
模块化开发是编程项目变大后的必然趋势,ECMAScript(Javascript)模块化目前最主流的是ES模块化方案,是随ECMAScript 2015官方发布的模块标准,覆盖所有ECMAScript运行环境;而CommonJS模块化方案出现得较早,用于服务器Node.js环境(截至2025年1月其默认模块化系统仍然是CommonJS, 但是同时支持ECMAScript)。因此对初学者和开发者,建议用ES模块。
ES模块概述。ESCMAScript模块,简称ES模块。从ESCMAScript 2015(即ES6)开始, ES模块化系统,是官方和最主流的模块化系统,目前ESCMAScript 2024(ES15)已经发布,得到了广泛的使用,覆盖所有运行环境,极大地标准化了ESCMAScipt语言和开发环境。 虽然服务器环境Nodejs的默认模块仍然是CommonJS, 但是其从Nodejs v12即开始支持ES模块。另外,TypeScript也支持ES模块.
在ECMA官方可以看到ECMAScript® 2015(简称ES6)到ECMAScript® 2024(简称ES15)标准的原文,注意ECMA不仅仅制定ECMAScript(JavaScript)标准,还包括其他标准,ECMAScript(JavaScript)标准对应的的ECMA-402标准编号. 其网址为 https://ecma-international.org/publications-and-standards/standards/ecma-402/ 。
以下是这两个模块化系统的具体关联与区别:
1.代码编写方式的差异
ES模块采用import和export来导入其他模块和公开给其他模块。如果我们看到某个js或者ts文件中,有import或者export操作,那么其就是采用了ES模块.
CommonJS模块采用require方法导入其他模块,使用module.exports导出内容给其他模块使用。因此我们看到某个js文件有require或者module.exports操作,那么其采用的就是CommonJS模块.
2.相通之处
ES模块与CommonJS模块对模块化概念是相同的,即每个文件都是模块。
每个文件中定义的变量/方法/类等对这个文件都是私有的,除非被显式导出。
并且一个模块的导出的内容只有被其他模块显式地导入才可以被这个其他模块使用。
尽管它们导入的语法不同,但是这些理念是相通的。
2.加载机制
- ES 模块:动态加载(不会缓存和使用缓存),即执行到的时候才执行加载操作,并且在编译时确定模块依赖关系,支持按需加载和懒加载。
- CommonJS:在 require 时立即加载(同步加载),并会缓存,后续其他模块使用会使用缓存(但是这样做会导致更新问题),适合服务器端环境。
3.文件扩展名
- ES 模块:在 package.json 中设置 "type": "module",使 .js 文件被视为 ES 模块。也可以使用 .mjs 扩展名使其成为ES模块文件.
- CommonJS:通常使用 .js 扩展名,默认情况下 Node.js 将其视为 CommonJS 模块。
4.ES 模块与 CommonJS 模块的互相操作
Node.js 提供了 ES 模块与 CommonJS 之间的互操作性,因此两者可以互相混用,方便了使用现有其他模块系统的模块(库)。你可以在 ES 模块中导入 CommonJS 模块,反之亦然。
// 某个ES 模块中导入另一个CommonJS 模块
import xxx from './xxx-commonjs.js'; // 假设 xxx-commonjs.js 使用 CommonJS 模块
// 某个CommonJS模块中 导入另一个ES 模块
const yyy= require('./yyy-esm.js'); // 假设 yyy-esm.js 使用 ES 模块
参考资料
1.《ECMA国际标准化组织官网》 https://ecma-international.org/publications-and-standards/standards/ecma-402/ 。
2.《Javascript权威指南》(原书第7版),Davaid Flanagan 著,李松峰 译。
3.《TypeScript入门与实战》,钟胜平 编著。