Node.js 模块化学习笔记

📚 Node.js 模块化学习笔记


📑 目录

  • 学习目标
  • 一、模块化简介
    • [1.1 什么是模块化](#1.1 什么是模块化)
    • [1.2 CommonJS 标准语法](#1.2 CommonJS 标准语法)
  • [二、ECMAScript 标准语法](#二、ECMAScript 标准语法)
    • [2.1 默认导出与导入](#2.1 默认导出与导入)
    • [2.2 命名导出与导入](#2.2 命名导出与导入)
    • [2.3 两种标准如何选择](#2.3 两种标准如何选择)
  • 三、包的概念
  • [四、npm 软件包管理器](#四、npm 软件包管理器)
    • [4.1 npm 基础使用](#4.1 npm 基础使用)
    • [4.2 安装所有依赖](#4.2 安装所有依赖)
    • [4.3 全局软件包](#4.3 全局软件包)
  • 五、知识总结
  • 六、常用命令速查

学习目标

  1. ✅ 了解 Node.js 模块化的概念和好处
  2. ✅ 了解 Node.js 中软件包的概念和引入
  3. ✅ 掌握 Node.js 的 npm 软件包管理器使用
  4. ✅ 了解 Node.js 中本地软件包与全局软件包区别

一、模块化简介

1.1 什么是模块化

💡 一句话理解:把代码拆分成一个个独立的文件(模块),每个模块有自己的作用域,可以按需加载和复用。

🎯 模块化的好处

好处 说明
独立作用域 每个文件都是独立的,变量不会互相污染
代码复用 写好的模块可以在多个地方使用
按需加载 需要哪个模块就加载哪个
易于维护 代码结构清晰,方便管理

💭 思考:这和前端 JS 直接写在 HTML 里完全不一样!以前所有变量都在全局作用域,很容易冲突。模块化让代码更有组织性,就像把工具分类放在不同的抽屉里。

🔒 模块的封装机制

Node.js 在执行模块代码时,会用函数封装器包裹起来:

javascript 复制代码
(function(exports, require, module, __filename, __dirname) {
  // 你的模块代码在这里
});

📝 笔记:这就是为什么模块内的变量默认是私有的,不会污染全局!


1.2 CommonJS 标准语法

🎯 Node.js 默认的模块化标准

📤 导出语法

javascript 复制代码
// utils.js
const baseURL = 'http://hmajax.jdfs.net';
const getArraySum = arr => arr.reduce((sum, item) => sum += item, 0);

// 导出
module.exports = {
  url: baseURL,           // 对外暴露叫 url
  arraySum: getArraySum   // 对外暴露叫 arraySum
};

📥 导入语法

javascript 复制代码
// index.js
const obj = require('./utils.js');

console.log(obj);                    // { url: '...', arraySum: [Function] }
const result = obj.arraySum([5, 1, 2, 3]);
console.log(result);                 // 11

⚠️ 路径选择规则

模块类型 写法 示例
内置模块 直接写模块名 require('fs')
自定义模块 写相对路径 require('./utils.js')
第三方模块 直接写包名 require('lodash')

💭 踩坑记录 :自定义模块一定要加 ./../,否则 Node.js 会认为是内置模块或 node_modules 里的包!我之前忘记加 ./ 报错了好几次 😅


二、ECMAScript 标准语法

💡 ES6 推出的模块化标准,前端工程化项目常用

2.1 默认导出与导入

📤 默认导出

javascript 复制代码
// utils.js
const baseURL = 'http://hmajax.jdfs.net';
const getArraySum = arr => arr.reduce((sum, item) => sum += item, 0);

// 默认导出(一个模块只能有一个默认导出)
export default {
  url: baseURL,
  arraySum: getArraySum
};

📥 默认导入

javascript 复制代码
// index.js
import obj from './utils.js';

console.log(obj);
const result = obj.arraySum([10, 20, 30]);
console.log(result);  // 60

⚠️ 重要:启用 ES Module

Node.js 默认使用 CommonJS,要使用 ES Module 需要在 package.json 中设置:

json 复制代码
{
  "type": "module"
}

📝 笔记 :设置了 "type": "module" 后,整个项目就都使用 ES Module 标准了。这时候就不能用 require 了,要用 import


2.2 命名导出与导入

📤 命名导出

javascript 复制代码
// utils.js
// 直接在定义时导出
export const baseURL = 'http://hmajax.jdfs.net';
export const getArraySum = arr => arr.reduce((sum, item) => sum += item, 0);

📥 命名导入

javascript 复制代码
// index.js
// 使用花括号,变量名必须和导出时一致
import { baseURL, getArraySum } from './utils.js';

console.log(baseURL);           // http://hmajax.jdfs.net
console.log(getArraySum);       // [Function]

const result = getArraySum([10, 21, 33]);
console.log(result);            // 64

🎯 命名 vs 默认导出对比

特性 默认导出 export default 命名导出 export
导出数量 一个模块只能有一个 可以有多个
导入方式 import xxx from '...' import { xxx } from '...'
导入时命名 可以自定义名字 必须和导出时同名
适用场景 整个模块作为一个整体导出 按需导出多个功能

💭 思考 :命名导出更灵活,可以按需引入。比如 lodash 就是用命名导出,我只引入 debouncethrottle,不会把整个库都打包进来。


2.3 两种标准如何选择

📊 CommonJS vs ECMAScript 对比

对比项 CommonJS ECMAScript (ES6)
语法 require / module.exports import / export
加载方式 运行时同步加载 编译时静态分析
Node.js 支持 ✅ 原生支持 需设置 "type": "module"
浏览器支持 ❌ 不支持 ✅ 现代浏览器支持
使用场景 Node.js 后端项目 前端工程化项目
Tree Shaking ❌ 不支持 ✅ 支持

🎯 选择建议

💡 我的理解

  • 纯 Node.js 后端项目 → CommonJS(简单直接)
  • 前端工程化项目(Webpack/Vite)→ ECMAScript(更好的 Tree Shaking)
  • 现代全栈项目 → ECMAScript(前后端统一标准)

三、包的概念

📦 什么是包

💡 定义 :将模块、代码、其他资料整合成一个文件夹,这个文件夹就叫

🏷️ 包的分类

类型 说明 示例
项目包 编写项目和业务逻辑的文件夹 我的网站项目
软件包 封装工具和方法供他人使用 lodash、dayjs

📋 包的要求

包文件夹必须 包含 package.json 文件,用于记录包的清单信息:

json 复制代码
{
  "name": "my-utils",
  "version": "1.0.0",
  "main": "index.js",    // ⭐ 入口文件
  "description": "工具函数包"
}

🔍 包的引入规则

引入一个包文件夹时,Node.js 会按以下顺序查找:

  1. 找包文件夹下的 index.js
  2. 如果没有 index.js,找 package.jsonmain 字段指定的文件

🎯 实践:创建自己的工具包

复制代码
utils/                    # 包文件夹
├── package.json          # 包清单
├── index.js             # 统一出口 ⭐
└── lib/                 # 工具模块文件夹
    ├── arr.js           # 数组工具
    └── str.js           # 字符串工具

utils/lib/arr.js

javascript 复制代码
const getArraySum = arr => arr.reduce((sum, item) => sum += item, 0);
module.exports = { getArraySum };

utils/lib/str.js

javascript 复制代码
const checkUser = name => name.length >= 2;
const checkPwd = pwd => pwd.length >= 6;
module.exports = { checkUser, checkPwd };

utils/index.js(统一出口):

javascript 复制代码
/**
 * 本文件是 utils 工具包的唯一出口
 * 作用:把所有工具模块方法集中起来,统一向外暴露
 */
const { getArraySum } = require('./lib/arr.js');
const { checkUser, checkPwd } = require('./lib/str.js');

// 统一导出所有函数
module.exports = {
  getArraySum,
  checkUser,
  checkPwd
};

使用包

javascript 复制代码
// index.js
const obj = require('./utils');  // ⭐ 注意:导入的是文件夹!

console.log(obj);
const result = obj.getArraySum([10, 20, 30]);
console.log(result);  // 60

💭 思考 :统一出口的设计模式很实用!用户只需要 require('./utils'),就能拿到所有工具函数,不用关心内部结构。这也是 npm 包的常见设计。


四、npm 软件包管理器

🎯 npm (Node Package Manager):Node.js 官方的软件包管理器,用于下载和管理依赖。

4.1 npm 基础使用

📋 使用步骤

bash 复制代码
# 1. 初始化项目(生成 package.json)
npm init -y

# 2. 下载软件包
npm i 软件包名称

# 3. 在代码中使用

📝 package.json 详解

json 复制代码
{
  "name": "my-project",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {        // ⭐ 生产依赖
    "dayjs": "^1.11.10"
  },
  "devDependencies": {}     // 开发依赖
}

🎯 实践:使用 dayjs 格式化日期

bash 复制代码
# 1. 初始化
npm init -y

# 2. 安装 dayjs
npm i dayjs
javascript 复制代码
// index.js
const dayjs = require('dayjs');

const now = dayjs();
console.log(now.format('YYYY-MM-DD HH:mm:ss'));

📁 安装后的文件结构

复制代码
my-project/
├── package.json          # 依赖清单
├── package-lock.json     # 锁定版本
├── index.js             # 项目代码
└── node_modules/        # ⭐ 下载的软件包
    └── dayjs/

💭 注意node_modules 文件夹通常很大,不要 提交到 Git!要在 .gitignore 中忽略它。


4.2 安装所有依赖

🤔 常见问题

Q:拿到了别人的项目,没有 node_modules,能运行吗?

不能! 因为缺少项目依赖的软件包源码。

Q:为什么不直接传递 node_modules

原因

  1. 文件夹太大,传输慢
  2. npm 有本地缓存,重新下载更快
  3. 不同系统可能有兼容性问题

🛠️ 解决方案

bash 复制代码
# 在项目目录下运行
npm i
# 或
npm install

这个命令会根据 package.json 中的 dependencies,自动下载所有依赖到 node_modules

📝 笔记 :这是协作开发的标配流程!克隆项目 → npm i → 运行代码。


4.3 全局软件包

📊 本地包 vs 全局包对比

类型 作用范围 存放位置 用途 安装方式
本地软件包 当前项目 node_modules 封装属性和方法 npm i 包名
全局软件包 本机所有项目 系统目录 封装命令和工具 npm i 包名 -g

🎯 常用全局包:nodemon

作用 :替代 node 命令,检测代码更改后自动重启程序。

bash 复制代码
# 全局安装
npm i nodemon -g

# 使用(代替 node 命令)
nodemon index.js

💡 效果演示

bash 复制代码
$ nodemon index.js
[nodemon] starting `node index.js`
Server running on port 3000

# 当你修改代码并保存...
[nodemon] restarting due to changes...
[nodemon] starting `node index.js`
Server running on port 3000

💭 体验 :开发神器!不用每次改代码都手动重启了。类似的工具还有 pm2(生产环境用)。

🔍 查看全局安装路径

bash 复制代码
npm root -g    # 查看全局包安装路径
npm list -g    # 查看已安装的全局包

五、知识总结

🧠 模块化思维导图

复制代码
Node.js 模块化
│
├── 模块化概念
│   ├── 每个文件是一个独立模块
│   ├── 独立作用域,变量不污染
│   ├── 按需加载,代码复用
│   └── 使用特定标准导出/导入
│
├── 两种模块化标准
│   ├── CommonJS(Node.js 默认)
│   │   ├── 导出:module.exports = {}
│   │   └── 导入:require('模块名')
│   │
│   └── ECMAScript(ES6)
│       ├── 默认导出:export default {}
│       ├── 默认导入:import xxx from '...'
│       ├── 命名导出:export const xxx
│       └── 命名导入:import { xxx } from '...'
│
├── 包的概念
│   ├── 项目包:写业务逻辑
│   ├── 软件包:封装工具方法
│   └── 必须有 package.json
│
└── npm 管理器
    ├── npm init -y          初始化
    ├── npm i 包名           安装本地包
    ├── npm i 包名 -g        安装全局包
    ├── npm i                安装所有依赖
    └── nodemon              自动重启工具

📋 两种模块化标准速查

操作 CommonJS ES Module
导出单个 module.exports = { a, b } export default { a, b }
导出多个 module.exports = { a, b } export const a = ...
导入默认 const obj = require('...') import obj from '...'
导入命名 const { a } = require('...') import { a } from '...'
启用方式 Node.js 默认 package.json 设置 "type": "module"

六、常用命令速查

🖥️ Node.js 命令

命令 作用
node 文件名.js 运行 JS 文件
nodemon 文件名.js 自动重启运行

📦 npm 命令

命令 作用
npm init 初始化项目(交互式)
npm init -y 初始化项目(使用默认值)⭐
npm i 包名 安装本地软件包 ⭐
npm i 包名 -g 安装全局软件包 ⭐
npm i 安装 package.json 中所有依赖 ⭐
npm uninstall 包名 卸载软件包
npm list 查看已安装的包
npm list -g 查看全局安装的包
npm root -g 查看全局包安装路径

⚠️ 注意事项

注意点 说明
文件夹名 不要用中文或特殊符号
node_modules 不要提交到 Git
自定义模块 引入时要加 ./
ES Module 需要设置 "type": "module"

❓ 疑问与待深入

💭 还需要进一步学习的内容

  1. package.json 更多字段scriptsdevDependenciespeerDependencies
  2. npm 镜像源:如何切换到淘宝镜像加速下载?
  3. npx 命令:临时执行包命令
  4. 模块循环依赖:怎么处理 A 依赖 B,B 又依赖 A?
  5. ESM 和 CJS 混用:一个项目能同时用两种标准吗?
  6. npm 包发布:如何发布自己的包到 npm?

📝 学习心得

这节课学到了 Node.js 最核心的模块化机制:

  1. 模块化让代码更有组织,避免了全局污染
  2. 两种标准各有适用场景,CommonJS 适合 Node.js 后端,ES Module 适合前端工程化
  3. 包的概念让代码可以复用,npm 让分享和使用代码变得简单
  4. 本地包 vs 全局包的区别要搞清楚,工具类的一般装全局

最重要的收获是理解了模块化的设计思想------把复杂系统拆分成独立、可复用的模块。这在任何编程语言中都是通用的思想!

相关推荐
linksinke1 小时前
Node.js 版本管理管理器的使用注意 - NVM
node.js·nvm·node多版本·node切换
mnasd1 小时前
RockyLinux 9.5 部署 Kubernetes1.35 集群
笔记
毕竟是shy哥1 小时前
CLIP:从自然语言监督中学习可迁移的视觉模型
学习
川石课堂软件测试1 小时前
作为一名测试工程师如何学习Kubernetes(k8s)技能
学习·测试工具·容器·职场和发展·kubernetes·测试用例·harmonyos
tryqaaa_1 小时前
学习日志(五)【php反序列化全加例题】【pop链,字符逃逸,session,伪协议】
android·学习·php·web·pop·session
li星野2 小时前
FastAPI 参数详解:路径参数、查询参数与请求体 —— 从入门到实战
服务器·学习·fastapi
東隅已逝,桑榆非晚2 小时前
编译和链接
c语言·笔记
05候补工程师2 小时前
【考研高数核心突破】极限的本质、高频解题套路与海涅定理深度解析(附经典例题思维导图式拆解)
经验分享·笔记·考研·算法
承渊政道2 小时前
【MySQL数据库学习】(MySQL数据类型)
数据库·学习·mysql·ubuntu·bash·数据库开发·数据库系统