【Node】CommonJs(cjs)

本文深入介绍了CommonJS规范,它是Node.js的模块化标准。详细讲解了Node.js中的全局对象global、模块作用域、module.exports和exports的使用,以及require函数的导入机制。通过实例展示了如何导出和导入数据,包括变量、函数、对象等,并探讨了模块查找顺序和第三方模块的加载规则。此外,还提到了ESModule作为CommonJS的替代方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

CommonJs

  • CommonJs 是 Node 的模块化规范
  • 在 Node 中,每个文件都是独立的模块
  • 在 Node 中,有一个全局对象 global (与网页中的 window 类似)
    全局作用域下创建的变量,会成为 global 的属性
    全局作用域下创建的函数,会成为 global 的方法
  • 模块内的变量不在全局作用域中,模块存在自己的作用域(相当于在一个函数内),所以不能随意调用模块之间的变量
let num = 0;
console.log(num, global.num); // 0 undefined
  • 创建全局变量:不用关键字声明(不推荐)
num = 0;
console.log(num, global.num); // 0 0
  • 实际上,Node 模块的代码都是包装在一个函数中的,并且函数在执行时,接收了 5 个实参,可通过 arguments 查看:
console.log(arguments);
[Arguments] {
  '0': {}, // module.exports 的引用,用于导出数据
  '1': [Function: require] {...}, // require 函数,用于导入数据
  '2': Module { // 当前模块 module
    path: 'e:\\node.js\\code\\newDemo\\js', // 当前模块所在目录的路径
    exports: {}, // module.exports 对象,用于导出数据
    filename: 'e:\\node.js\\code\\newDemo\\js\\operation.js', // 当前模块的路径
    // ...
  },
  '3': 'e:\\node.js\\code\\newDemo\\js\\operation.js', // 当前模块的路径
  '4': 'e:\\node.js\\code\\newDemo\\js' // 当前模块所在目录的路径
}
  • 接收这 5 个实参的形参:(exports, require, module, __filename, __dirname) => {}
    1. exports:用于导出数据;默认为空对象;是 module.exports 的引用
    2. require:用于导入数据;是一个函数,返回 [被导入模块所导出的数据],即 [被导入模块的 module.exports]
    3. module:代表当前模块,存有与当前模块相关的信息
    4. __filename:当前模块的路径
    5. __dirname:当前模块所在目录的路径
console.log("module.exports", module.exports); // module.exports {}
console.log("require", require); // require [Function: require] { …… }
console.log(exports === module.exports); // true
console.log("__filename", __filename); // __filename e:\node.js\code\newDemo\js\operation.js
console.log("__dirname", __dirname); // __dirname e:\node.js\code\newDemo\js



require - 导入数据

  • require('文件标识'),返回 [被导入模块所导出的数据],即 [被导入模块的 module.exports]
  • 模块分 3 大类:核心模块、自定义模块、第三方模块
    ① 核心模块:Node 的内置模块,模块标识是 模块名
    ② 自定义模块:用户自己创建的模块,模块标识是 文件路径
    ③ 第三方模块:需要手动下载;模块标识是 模块名
  • 模块查找顺序:
    ① 核心模块:require('fs')
    ② 自定义模块:require('./cjs1') ( 可以不写后缀!!! )
    会先按照确切的文件名进行加载 → 补全 .js 进行加载 → 补全 .json 进行加载 → 补全 .node 进行加载
    ③ 第三方模块:require('mysql')
    会到同级的 node_modules 目录中寻找 mysql 目录,找不到则往上一级的 node_modules 目录找
    在 mysql 目录下,找到 package.json 中的 main 字段,读取入口文件
    如果没有 package.json,或者 main 字段 [入口不存在] / [无法解析],则 node 会找该目录下的 index.js


module.exports - 导出数据

① 将需要导出的数据赋值给 module.exports → module.exports = 数据
  • 导出一个数据:
/* cjs1.js */
console.log("cjs1.js");
module.exports = 10; // 导出一个数值
/* cjs2.js */
const num = require("./cjs1"); // 导入数据
console.log("cjs1", num); // cjs1 10

导入时,会先执行一遍 [被导入文件] !!!所以上例的输出顺序为 cjs1.js - cjs1 10

  • 导出一个函数:
/* cjs1.js */
// 导出一个函数
module.exports = function showNum() {
    console.log("num");
};
/* cjs2.js */
const fun = require("./cjs1"); // 导入函数
console.log("cjs1", fun); // csj1 [Function: showNum]

导出匿名函数:

/* cjs1.js */
// 导出一个匿名函数
module.exports = function () {
    console.log("num");
};
/* cjs2.js */
const fun = require("./cjs1");
console.log("cjs1", fun); // cjs1 [Function (anonymous)]

导出箭头函数:

/* cjs1.js */
// 导出一个箭头函数
module.exports = () => {
    console.log("num");
};
/* cjs2.js */
const fun = require("./cjs1");
console.log("cjs1", fun); // cjs1 [Function (anonymous)]
  • 导出一个对象:
/* cjs1.js */
function showNum() {
    console.log("num");
}
let num = 10;
module.exports = {
    cjs1ShowNum: showNum,
    cjs1Num: num,
};
/* cjs2.js */
const cjs1 = require("./cjs1");
console.log("cjs1", cjs1); // cjs1 { cjs1ShowNum: [Function: showNum], cjs1Num: 10 }

导出时可配合 [对象属性的简写]:

/* cjs1.js */
function showNum() {
    console.log("num");
}
let num = 10;
module.exports = { showNum, num }; // 属性名与变量名一样时,可以省略属性名不写
/* cjs2.js */
const cjs1 = require("./cjs1");
console.log("cjs1", cjs1); // cjs1 { showNum: [Function: showNum], num: 10 }

导入可配合 [解构赋值]:

/* cjs2.js */
const { showNum, num } = require("./cjs1.js");
console.log("showNum", showNum); // showNum [Function: showNum]
console.log("num", num); // num 10

② 将需要导出的数据设置为 module.exports 的属性:module.exports.数据名 = 数据值
/* cjs1.js */
let num = 10; // 定义一个变量
module.exports.cjs1Num = num; // 导出这个变量

// 定义一个函数
function showNum() {
    console.log("num");
}
module.exports.cjs1ShowNum = showNum; // 导出这个函数
/* cjs2.js */
const cjs1 = require("./cjs1");
console.log("cjs1", cjs1); // cjs1 { cjs1Num: 10, cjs1ShowNum: [Function: showNum] }



exports - 导出数据

  • 将需要导出的数据设置为 exports 的属性:exports.数据名 = 数据值
/* cjs1.js */
let num = 10; // 定义一个变量
exports.cjs1Num = num; // 导出这个变量

// 定义一个函数
function showNum() {
    console.log("num");
}
exports.cjs1ShowNum = showNum; // 导出这个函数
/* cjs2.js */
const cjs1 = require("./cjs1");
console.log("cjs1", cjs1); // cjs1 { cjs1Num: 10, cjs1ShowNum: [Function: showNum] }



module.exports & exports

  • 文件导出的是 module.exports,而 exportsmodule.exports 的引用

    ∴ 直接给 exports 赋值是修改不了 module.exports

    ∴ 通过直接赋值导出的操作,只能由 module.exports 完成,不能使用 exports

/* cjs1.js */
function showNum() {
    console.log("num");
}
let num = 10;
exports = { showNum, num };
/* cjs2.js */
const cjs1 = require("./cjs1.js");
console.log("cjs1", cjs1); // cjs1 {}

可以看到导入的是空对象 {},即什么数据都没获取到

  • 如果多次使用 module.exports 通过直接赋值导出数据,后面的会覆盖前面的
/* cjs1.js */
let num = 10;
module.exports = { num }; // 给 module.exports 赋值
function showNum() {
    console.log("num");
}
module.exports = { showNum }; // 再给 module.exports 赋值
/* cjs2.js */
const cjs1 = require("./cjs1.js");
console.log("cjs1", cjs1); // cjs1 { showNum: [Function: showNum] }

同理,如果我们先给 module.exports 设置属性,然后又对 module.exports 赋值,则导出的是赋值给 module.exports 的数据!

/* cjs1.js */
let num = 10;
module.exports.num = num; // 给 module.exports 设置属性
function showNum() {
    console.log("num");
}
module.exports = { showNum }; // 再给 module.exports 赋值
/* cjs2.js */
const cjs1 = require("./cjs1.js");
console.log("cjs1", cjs1); // cjs1 { showNum: [Function: showNum] }



模块化 demo

思路:[ 数据 ]、[ 方法 ]、[ 逻辑处理 ] 分开放置

/* data.js */
let dataObj = {
    name: "superman",
    age: 21
}
module.exports = dataObj;
/* function.js */
function showName(obj) {
    console.log('my name is ' + obj.name);
}
module.exports = showName;
/* operation.js */
let showName = require('./function.js');
let dataObj = require('./data.js');
showName(dataObj); // my name is superman



ESModule(esm)



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JS.Huang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值