Node.js--CommonJS 模块化规范详解:使用方法、缓存机制与模块解析

目录

[Node.js CommonJS 模块化规范详解](#Node.js CommonJS 模块化规范详解)

[1. CommonJS 模块化规范简介](#1. CommonJS 模块化规范简介)

[CommonJS 主要特点](#CommonJS 主要特点)

[2. CommonJS 模块的基本使用](#2. CommonJS 模块的基本使用)

示例1:导出和导入模块

运行程序

[3. module.exports vs exports 的使用](#3. module.exports vs exports 的使用)

[示例2:使用 exports 导出多个方法](#示例2:使用 exports 导出多个方法)

[示例3:使用 module.exports 导出单个函数](#示例3:使用 module.exports 导出单个函数)

[4. CommonJS 的模块缓存机制](#4. CommonJS 的模块缓存机制)

示例4:模块缓存机制

[5. CommonJS 的 require 解析规则](#5. CommonJS 的 require 解析规则)

[6. 结论](#6. 结论)

在 Node.js 中,CommonJS(CJS)是最常见的模块化规范,它允许开发者将代码拆分为独立的模块,便于复用和管理。本文将详细介绍 CommonJS 的核心概念、使用方法,并提供完整代码示例,帮助你深入理解并应用 CommonJS 进行模块化开发。


1. CommonJS 模块化规范简介

CommonJS 规范的核心思想是一个文件就是一个模块 ,每个模块都有自己的作用域,默认情况下,模块内部定义的变量、函数、对象等不会污染全局作用域。

CommonJS 主要特点

  1. require 导入模块
  2. module.exports / exports 导出模块
  3. 同步加载(适用于服务器端)
  4. 模块缓存(require 同一个模块时不会重复加载)

2. CommonJS 模块的基本使用

示例1:导出和导入模块

创建 math.js,定义数学计算功能,并使用 module.exports 导出。

文件名:math.js(JavaScript)

javascript 复制代码
// math.js
const mathOperations = {
    add: (a, b) => a + b,
    subtract: (a, b) => a - b,
    multiply: (a, b) => a * b,
    divide: (a, b) => (b !== 0 ? a / b : "Error: Division by zero")
};

// 导出模块
module.exports = mathOperations;

文件名:app.js(JavaScript)

javascript 复制代码
// app.js
const math = require("./math"); // 使用 require 导入模块

console.log("加法 5 + 3 =", math.add(5, 3)); 
console.log("减法 10 - 4 =", math.subtract(10, 4)); 
console.log("乘法 6 * 7 =", math.multiply(6, 7)); 
console.log("除法 20 / 5 =", math.divide(20, 5)); 
console.log("除法 10 / 0 =", math.divide(10, 0)); // 测试除数为0的情况

运行程序

bash 复制代码
node app.js

输出结果

bash 复制代码
加法 5 + 3 = 8
减法 10 - 4 = 6
乘法 6 * 7 = 42
除法 20 / 5 = 4
除法 10 / 0 = Error: Division by zero

3. module.exports vs exports 的使用

在 CommonJS 规范中,module.exports 是实际的导出对象,而 exports 只是它的引用。

示例2:使用 exports 导出多个方法

文件名:stringUtils.js(JavaScript)

javascript 复制代码
// stringUtils.js
exports.toUpperCase = function (str) {
    return str.toUpperCase();
};

exports.toLowerCase = function (str) {
    return str.toLowerCase();
};

文件名:app.js(JavaScript)

javascript 复制代码
// app.js
const stringUtils = require("./stringUtils");

console.log(stringUtils.toUpperCase("hello")); // 输出: HELLO
console.log(stringUtils.toLowerCase("WORLD")); // 输出: world

运行程序

bash 复制代码
node app.js

输出结果

bash 复制代码
HELLO
world

示例3:使用 module.exports 导出单个函数

文件名:greet.js(JavaScript)

javascript 复制代码
// greet.js
module.exports = function(name) {
    return `Hello, ${name}!`;
};

文件名:app.js(JavaScript)

javascript 复制代码
// app.js
const greet = require("./greet");
console.log(greet("鼠鼠"));

运行程序

bash 复制代码
node app.js

输出

javascript 复制代码
Hello, 鼠鼠!

4. CommonJS 的模块缓存机制

在 CommonJS 规范下,require 只会第一次加载 模块时执行其中的代码,之后会缓存模块内容,再次 require 时不会重新执行模块,而是直接返回缓存的结果。

示例4:模块缓存机制

文件名:counter.js(JavaScript)

javascript 复制代码
// counter.js
let count = 0;

exports.increment = function () {
    count++;
    return count;
};

文件名:app.js(JavaScript)

javascript 复制代码
// app.js
const counter1 = require("./counter");
const counter2 = require("./counter");

console.log(counter1.increment()); // 输出: 1
console.log(counter2.increment()); // 输出: 2 (同一个缓存实例)
console.log(counter1.increment()); // 输出: 3

运行程序

bash 复制代码
node app.js

输出结果

bash 复制代码
1
2
3

解释:

  • require("./counter") 只在第一次执行 counter.js 的代码,count 被缓存。
  • 后续 require("./counter") 直接返回缓存的 count 变量,而不是重新执行 counter.js 文件。

5. CommonJS 的 require 解析规则

在使用 require() 导入模块时,Node.js 会按以下顺序解析模块路径:

  1. 内置模块 (如 fs、path 等)
  2. 文件模块
    • require('./math')(加载 math.js)
    • require('../utils')(加载上一级目录的 utils.js)
  3. 第三方模块 (默认在 node_modules 查找)
    • require('express')(加载 node_modules/express 目录下的 index.js)
  4. 目录模块
    • 如果 require('./myModule') 指向的是一个文件夹,Node.js 会查找该文件夹中的 package.json,尝试加载 main 字段指向的文件。
    • 如果 package.json 不存在或 main 字段未定义,则尝试加载 index.js。

6. 结论

  • CommonJS 规范 使用 module.exports 导出模块,require 导入模块。
  • 模块作用域:每个文件是一个独立的模块,变量不会污染全局。
  • 模块缓存 :require 只会执行模块一次,之后直接返回缓存的对象。
  • module.exports vs exports :exports 只是 module.exports 的引用,不能直接赋值 exports = {...},否则会失效。
  • 模块解析规则 :Node.js 先查找内置模块,再查找文件模块,最后查找 node_modules 目录。

希望这篇文章能帮助你理解 Node.js CommonJS 模块化规范,掌握如何使用 module.exports 和 require 进行模块化开发!

相关推荐
鬼手点金4 小时前
nanoGPT/nanochat 能做出 DeepSeek/Qwen 这样的大模型吗?
服务器·前端·javascript·bug·openclaw
软件技术NINI4 小时前
美妆商城html+Css+js 4页
javascript·css·html
蛋蛋的就会顺顺的4 小时前
hot100 p0——栈,贪心算法,动态规划
java·前端·javascript·算法·leetcode·力扣
程序员Sunday4 小时前
TypeScript 的 any、unknown、never 有什么区别?
前端·面试·typescript
朱涛的自习室4 小时前
70 美金的 Beyond Compare,我让 Gemini 4 和 DeepSeek 造个开源免费版(Day 2)
android·前端·人工智能
码艺-Alimjan5 小时前
Tauri 源码备份 · 打包 & 解压 总结,源码收集之路
前端·javascript·vue.js
小马不起床5 小时前
零基础玩转 FastAPI_11:前端后台管理页面
前端·状态模式·fastapi
子非鱼a7 小时前
【文件上传】一个普普通通的edu16
前端
美狐美颜SDK开放平台7 小时前
直播APP如何实现美白滤镜功能?视频美颜SDK技术开发方案详解
前端·数据库·人工智能·音视频·美颜sdk·直播美颜sdk·视频美颜sdk
silvamux_7 小时前
curl 测试 OpenAI 兼容 API 的完整流程
java·人工智能·缓存·ai·oneapi