CommonJS

CommonJS 是什么?

CommonJS 是 Node.js 采用的模块规范,主要用于服务器端 JavaScript 开发。它使用同步加载模块的方式,因为服务器端文件都在本地,读取速度快。

核心语法

1. 导出模块(Exports)

CommonJS 提供了两种导出方式:

方式一:module.exports

javascript 复制代码
// math.js
module.exports = {
  add: function(a, b) {
    return a + b;
  },
  subtract: function(a, b) {
    return a - b;
  }
};

// 或者导出单个函数/类
module.exports = function(a, b) {
  return a + b;
};

// 或者导出一个类
module.exports = class Calculator {
  add(a, b) {
    return a + b;
  }
};

方式二:exports(是 module.exports 的引用)

javascript 复制代码
// math.js
exports.add = function(a, b) {
  return a + b;
};

exports.subtract = function(a, b) {
  return a - b;
};

⚠️ 注意:exportsmodule.exports 的区别

javascript 复制代码
// ❌ 错误用法 - 这样会切断 exports 和 module.exports 的引用关系
exports = function(a, b) {
  return a + b;
};

// ✅ 正确用法
module.exports = function(a, b) {
  return a + b;
};

// ✅ 或者
exports.add = function(a, b) {
  return a + b;
};

2. 导入模块(Require)

javascript 复制代码
// 导入整个模块
const math = require('./math');
math.add(1, 2);

// 使用解构导入
const { add, subtract } = require('./math');
add(1, 2);

// 导入核心模块
const fs = require('fs');
const path = require('path');

// 导入第三方模块
const express = require('express');
const lodash = require('lodash');

详细特性

3. 模块缓存

javascript 复制代码
// counter.js
let count = 0;
module.exports = {
  increment: () => ++count,
  getCount: () => count
};

// main.js
const counter1 = require('./counter');
const counter2 = require('./counter');

counter1.increment(); // 1
console.log(counter2.getCount()); // 1 - 同一个实例!

// 模块只会加载一次,后续 require 返回缓存的模块
console.log(counter1 === counter2); // true

4. 模块查找机制

javascript 复制代码
// 1. 核心模块(优先级最高)
require('fs');  // Node.js 内置模块

// 2. 文件模块
require('./math');        // 当前目录下的 math.js
require('./math.js');     // 明确指定后缀
require('../utils/math'); // 上级目录

// 3. 文件夹模块
require('./myModule');    
// 查找顺序:
// - ./myModule/package.json 的 main 字段
// - ./myModule/index.js
// - ./myModule/index.json
// - ./myModule/index.node

// 4. node_modules 模块
require('express');
// 查找顺序(从当前目录向上递归):
// - ./node_modules/express
// - ../node_modules/express
// - ../../node_modules/express
// - 直到根目录

5. 循环依赖处理

javascript 复制代码
// a.js
console.log('a 开始');
exports.done = false;
const b = require('./b');
console.log('在 a 中,b.done =', b.done);
exports.done = true;
console.log('a 结束');

// b.js
console.log('b 开始');
exports.done = false;
const a = require('./a');
console.log('在 b 中,a.done =', a.done);
exports.done = true;
console.log('b 结束');

// main.js
const a = require('./a');
console.log('main 中,a.done =', a.done);

/* 输出:
a 开始
b 开始
在 b 中,a.done = false  // a 还未执行完,只获取到部分导出
b 结束
在 a 中,b.done = true
a 结束
main 中,a.done = true
*/

6. 模块包装

每个模块在执行前,Node.js 会将代码包装在一个函数中:

javascript 复制代码
(function(exports, require, module, __filename, __dirname) {
  // 你的模块代码
  const math = require('./math');
  module.exports = { /* ... */ };
});

所以在模块中可以直接使用:

  • exports - 导出对象的引用
  • require - 导入函数
  • module - 当前模块对象
  • __filename - 当前文件的绝对路径
  • __dirname - 当前文件所在目录的绝对路径

CommonJS vs ES6 模块

特性 CommonJS ES6 Module
语法 require/module.exports import/export
加载方式 同步加载 异步加载
加载时机 运行时加载 编译时加载
输出 值的拷贝 值的引用
this 指向当前模块 undefined
使用环境 Node.js 浏览器和 Node.js
动态导入 支持(天然) 需要 import()
javascript 复制代码
// CommonJS - 运行时加载,可以动态 require
const moduleName = Math.random() > 0.5 ? './a' : './b';
const module = require(moduleName); // ✅ 可以

if (condition) {
  const math = require('./math'); // ✅ 可以
}

// ES6 - 编译时加载,import 必须在顶层
import math from './math'; // ✅ 必须在顶层

if (condition) {
  import math from './math'; // ❌ 不可以
  import('./math').then(math => {}); // ✅ 需要用动态 import
}

实际应用示例

javascript 复制代码
// logger.js - 工具模块
const chalk = require('chalk'); // 第三方库

class Logger {
  info(msg) {
    console.log(chalk.blue('[INFO]'), msg);
  }
  
  error(msg) {
    console.log(chalk.red('[ERROR]'), msg);
  }
}

module.exports = new Logger(); // 导出单例

// config.js - 配置模块
module.exports = {
  port: process.env.PORT || 3000,
  db: {
    host: 'localhost',
    port: 5432
  }
};

// app.js - 主应用
const express = require('express');
const logger = require('./logger');
const config = require('./config');

const app = express();

app.listen(config.port, () => {
  logger.info(`Server running on port ${config.port}`);
});
相关推荐
孙牛牛7 小时前
实战分享:一招解决嵌套依赖版本失控问题,以 undici 为例
前端
uhakadotcom7 小时前
NVIDIA CUDA Python 常用 API 及详细教程
算法·面试·github
用户52709648744907 小时前
Git 最佳实践
前端
星秀日7 小时前
JavaWeb--Ajax
前端·javascript·ajax
4_0_47 小时前
全栈视角:从零构建一个现代化的 Todo 应用
前端·node.js
BumBle8 小时前
uniapp 用css实现圆形进度条组件
前端·vue.js·uni-app
杏花春雨江南8 小时前
npm error Could not resolve dependency:
前端·npm·node.js
嫂子的姐夫8 小时前
10-七麦js扣代码
前端·javascript·爬虫·python·node.js·网络爬虫
Komorebi_99998 小时前
Vue3 + TypeScript provide/inject 小白学习笔记
前端·javascript·vue.js