CommonJS 是一种为 JavaScript 提供模块化支持的规范,它最初的目标是为服务器端 JavaScript 提供模块化机制,以下是关于 CommonJS 的详细介绍:
1、核心概念
模块:在 CommonJS 中,一个文件就是一个模块,拥有单独的作用域,每个模块内定义的变量、函数、对象等都是私有的,外部无法直接访问,除非通过特定的方式将其暴露出去,在一个math.js
文件中定义的数学计算函数,默认情况下只能在该文件内部使用。
模块系统:CommonJS 提供了一套完整的模块系统,包括模块的定义、导入和导出等功能,通过这个模块系统,开发者可以将复杂的应用程序拆分成多个小的、可管理的模块,每个模块负责特定的功能,从而提高代码的可维护性和可扩展性。
2、基本用法
模块导出:
math.js
文件中,可以这样导出add
和subtract
函数:
function add(a, b) { return a + b; } function subtract(a, b) { return a b; } module.exports = { add, subtract, };
exports
是module.exports
的一个快捷方式,但需要注意的是,在使用exports
时不能直接给其赋值,否则会覆盖整个模块的导出对象,可以通过添加属性的方式向exports
对象上添加新的方法和属性。
exports.sayHello = function(name) {
returnHello, ${name}!
;
};
模块引入:使用require()
函数来引入其他模块。require()
接受模块的路径或模块的名称作为参数,并返回该模块的导出对象,在app.js
文件中引入math.js
和greet.js
模块:
const math = require('./math'); const greet = require('./greet'); console.log(math.add(2, 3)); // 输出 5 console.log(greet.sayHello('World')); // 输出 Hello, World!
3、模块加载机制
加载流程
路径解析:当使用require()
函数引入模块时,Node.js 会根据传入的参数解析模块的路径,如果是本地模块(以./
或../
开头),则在当前文件所在的目录下查找对应的文件;如果是核心模块(如fs
、http
等),则直接从 Node.js 内置模块中加载。
文件定位:Node.js 会尝试按顺序查找以下几种文件格式:.js
文件、.json
文件、.node
文件,如果找到了相应的文件,就将其作为模块加载;如果没有找到,则会抛出错误。
编译和执行:找到模块文件后,Node.js 会对其中的 JavaScript 代码进行编译,然后执行模块代码,在执行过程中,会将模块中的导出内容缓存起来,以便后续再次引入该模块时可以直接使用缓存中的实例,提高性能。
单例模式与缓存机制:CommonJS 模块是单例模式,即每个模块在第一次加载后会被缓存,如果多次require()
同一个模块,返回的将是相同的实例,这意味着在模块内部定义的状态或数据在多次引用时是共享的,在一个counter.js
文件中定义了一个计数器变量count
,每次调用increment
方法会增加count
的值,当在多个文件中分别引入counter.js
模块时,它们共享同一个count
变量。
4、实际应用场景
服务端开发:CommonJS 是 Node.js 中默认的模块系统,因此在服务端开发中得到了广泛的应用,开发者可以使用 CommonJS 规范将服务器端的逻辑分成不同的模块,如处理用户请求的模块、数据库操作的模块、业务逻辑的模块等,从而提高代码的组织性和可维护性,在一个基于 Express 框架的 Web 应用中,可以将路由处理、中间件、控制器等分别放在不同的模块文件中,然后在主文件中引入这些模块并进行配置。
命令行工具开发:许多命令行工具也是用 CommonJS 编写的,通过将不同的功能封装成模块,可以使命令行工具的结构更加清晰,便于扩展和维护,一些代码格式化工具、打包工具等都可以使用 CommonJS 来实现。
桌面应用开发:虽然 CommonJS 最初是为服务器端设计的,但在桌面应用开发中也可以使用,使用 Electron 框架开发的桌面应用,可以在其中使用 CommonJS 规范来组织和管理代码。
CommonJS 作为一种重要的 JavaScript 模块化规范,以其独特的核心概念、灵活的基本用法、高效的模块加载机制以及广泛的实际应用场景,为 JavaScript 项目的开发提供了强大的支持,无论是服务端、命令行工具还是桌面应用开发,CommonJS 都展现出了其卓越的代码组织能力和可维护性优势,成为 JavaScript 开发者不可或缺的工具之一。