Node.js CommonJS 模块规范
CommonJS 是 Node.js 采用的模块规范,定义了模块的导出和引入标准。
规范定义
CommonJS 规定:
- 每个文件就是一个模块,有独立作用域
- 通过 module.exports 导出模块接口
- 通过 require 引入其他模块
- 模块加载是同步的
module 对象
每个模块内置 module 对象:
JavaScript
console.log(module);
// Module {
// id: '.', // 模块标识
// exports: {}, // 导出对象
// filename: '/path/to/file.js',
// loaded: false, // 是否已加载
// parent: Module, // 引用者模块
// children: [], // 子模块列表
// paths: [...] // 模块查找路径
// }
module.exports
JavaScript
// 导出对象
module.exports = {
name: 'utils',
version: '1.0.0'
};
// 导出函数
module.exports = function(a, b) {
return a + b;
};
// 导出类
module.exports = class User {
constructor(name) {
this.name = name;
}
};
exports 简写
JavaScript
// exports 是 module.exports 的引用
exports.add = (a, b) => a + b;
exports.multiply = (a, b) => a * b;
// 等价于
module.exports.add = (a, b) => a + b;
module.exports.multiply = (a, b) => a * b;
exports 使用限制
JavaScript
// ❌ 错误:重新赋值断开引用
exports = { add: () => {} }; // 不会导出
// ❌ 错误:不能直接赋值
exports = function() {}; // 不会导出
// ✅ 正确:添加属性
exports.add = () => {};
// ✅ 正确:使用 module.exports
module.exports = { add: () => {} };
exports 只能添加属性,不能重新赋值。
require 函数
JavaScript
// 引入核心模块
const fs = require('fs');
// 引入文件模块
const utils = require('./utils');
const config = require('../config');
// 引入第三方模块
const express = require('express');
// 引入目录模块
const routes = require('./routes'); // 加载 routes/index.js
require 返回值
JavaScript
// 返回 module.exports 的值
const utils = require('./utils');
// utils 就是 ./utils.js 的 module.exports
模块标识
JavaScript
// 相对路径标识
require('./utils');
require('../config');
// 绝对路径标识
require('/home/user/module');
// 模块名标识(核心模块或 node_modules)
require('fs');
require('express');
扩展名处理
JavaScript
// Node.js 自动尝试扩展名
require('./utils');
// 查找顺序:
// ./utils.js
// ./utils.json
// ./utils.node
// ./utils/index.js
// ./utils/index.json
// ./utils/index.node
加载时机
JavaScript
// CommonJS 是同步加载
const a = require('./a'); // 加载完成才继续
const b = require('./b'); // 加载完成才继续
// 代码执行顺序
console.log('1'); // 1
require('./a'); // 执行 a.js
console.log('2'); // 2(a.js 执行完)
动态加载
JavaScript
// require 可在任意位置动态调用
function loadModule(name) {
return require(name);
}
// 条件加载
if (process.env.NODE_ENV === 'test') {
const mock = require('./mock');
}
// 循环加载
const modules = ['a', 'b', 'c'].map(name => require(`./${name}`));
规范特点
| 特点 | 说明 |
|---|---|
| 同步加载 | 适合服务端,不适合浏览器 |
| 运行时加载 | 无法静态分析和优化 |
| 值复制 | 导出值是复制,不是引用 |
| 单例模式 | 模块只加载一次 |
| 动态加载 | require 可在任意位置使用 |
要点总结
- CommonJS 是 Node.js 原生模块规范
- module.exports 是真正的导出对象
- exports 是 module.exports 的引用,只能添加属性
- require 同步加载模块,返回 module.exports
- 模块缓存后不会重复加载
📝 发现内容有误?点击此处直接编辑