diff --git "a/\347\275\227\347\232\223\346\231\250/20260306-nodejs\345\205\245\351\227\250.md" "b/\347\275\227\347\232\223\346\231\250/20260306-nodejs\345\205\245\351\227\250.md" new file mode 100644 index 0000000000000000000000000000000000000000..721936b0cd7b387550355e05d30f0211b01abf1f --- /dev/null +++ "b/\347\275\227\347\232\223\346\231\250/20260306-nodejs\345\205\245\351\227\250.md" @@ -0,0 +1,263 @@ +## 笔记 + +### Node.js介绍 + +Node.js不是一门新语言,只是JavaScript不在浏览器里跑,而是在Node运行时跑。Node提供了文件系统、网络、进程、流等服务端能力。 + +所以 Node.js分成三层: +1. **JavaScript 语法层**:变量、函数、对象、类、模块、异步 +2. **Node 运行时层**:`fs`、`path`、`http`、`process`、`Buffer`、`Stream` +3. **项目开发层**:Express、路由、中间件、分层、数据库、鉴权 + +### Node.js在控制台上的输入与输出 + +#### 输出: +核心方式:console.log()(和浏览器一致) + +其他辅助:console.error()(错误输出)、console.warn()(警告输出) + +本质:同步操作,直接向process.stdout(标准输出流)打印内容 + +#### 输入: + +##### 回调写法 + +- 基础配置 + + - 模块引入:`const readline = require('readline');`(原生基础版 readline) + + - 接口创建:`const rl = readline.createInterface({input: process.stdin, output: process.stdout});`(1 个实例可复用) + +- 调用方式:`rl.question(query, callback)` + - `query`:必填字符串,控制台展示的提问提示语(如`'请输入考试分数:'`) + - `callback(answer)`:用户输入并回车后触发的函数,`answer`固定为字符串类型(即使输入数字也是`'90'`而非`90`) + - 无返回值 +- 执行特性:异步非阻塞,调用`rl.question`后代码立即继续执行,不会等待用户输入 + +- 完整示例 + + ```js + // 引入readline模块 + const readline = require('readline'); + // 创建输入输出接口 + const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout + }); + + // 调用question方法获取用户输入(考试分数) + rl.question('请输入考试分数:', (answer) => { + // answer是字符串类型,需转换为数字 + const score = Number(answer); + // 输出处理后的结果 + console.log(`你输入的考试分数是:${score},类型为:${typeof score}`); + // 多轮输入示例(嵌套回调) + rl.question('请输入你的姓名:', (name) => { + console.log(`姓名:${name},分数:${score}`); + // 关闭输入接口,否则程序不会退出 + rl.close(); + }); + }); + + // 验证异步特性:此代码会先执行,因为question是异步的 + console.log('代码已触发输入请求,等待用户输入...'); + ``` + +##### async/await 写法 + +- 基础配置 + + - 模块引入:`const readline = require('readline/promises');`(Promise 增强版 readline) + + - 接口创建:与回调写法一致 → `const rl = readline.createInterface({input: process.stdin, output: process.stdout});` + +- 前置条件:必须包裹在`async`标记的函数内(`async`是使用`await`的唯一前提) +- 调用方式:`let 变量 = await rl.question(query)` + - `await`:暂停函数执行,直到用户输入并回车,Promise 兑现后才继续向下执行 + - `query`:同回调写法,仅需传入提示语字符串,无需回调函数 + - 返回值:`Promise`,即一个承载字符串类型结果的 Promise 对象;`Promise`是异步结果的 “容器”,``表示容器最终兑现时的结果类型为字符串(用户输入的内容) + +- 执行特性:async 标记的函数外部异步、内部同步,await 专等 Promise 兑现,输入按代码顺序执行,无需嵌套即可拿到输入值。 + +- 完整示例 + + ```js + // 引入Promise版本的readline模块 + const readline = require('readline/promises'); + // 创建输入输出接口 + const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout + }); + + // 定义异步函数(必须加async) + async function getExamInfo() { + // 打印rl.question的返回值(验证Promise类型) + const questionPromise = rl.question('请输入考试分数:'); + console.log('rl.question的返回值类型:', typeof questionPromise); // 输出 object + console.log('是否为Promise对象:', questionPromise instanceof Promise); // 输出 true + + // 等待Promise兑现,拆解出内部的字符串值 + const scoreStr = await questionPromise; + // 等价写法:const scoreStr = await rl.question('请输入考试分数:'); + + // 转换为数字(正确写法:先await拆出字符串,再转数字) + const score = Number(scoreStr); + + // 等待用户输入姓名,线性执行,无嵌套 + const name = await rl.question('请输入你的姓名:'); + + // 输出结果 + console.log(`姓名:${name},分数:${score},分数类型:${typeof score}`); + + // 关闭输入接口 + rl.close(); + } + + // 调用异步函数 + getExamInfo(); + + // 验证await的暂停特性:此代码先执行,但getExamInfo内部会等待输入 + console.log('异步函数已调用,等待用户输入...'); + ``` + + +##### 核心差异总结 + +| 特性 | 回调写法 | async/await 写法 | +| :-------------: | :------------------------: | :------------------------: | +| 执行顺序 | 异步无等待,外部代码先执行 | 异步有等待,按代码顺序执行 | +| 数据作用域 | 仅回调内可用 | async 函数内全域可用 | +| 代码结构 | 多层嵌套,可读性差 | 线性执行,无嵌套 | +| 学习 / 维护成本 | 需理解回调异步逻辑,成本高 | 接近同步思维,成本低 | +| 数据转换 | 回调内转换 | 直接包裹 await 结果转换 | + +## 作业 + +### 选择题 + +Node.js 是基于哪个 JavaScript 引擎开发的? + +**答:B. V8** + +以下哪个不是 Node.js 的核心特性? + +**答:B. 多线程** + +Node.js 最适合开发以下哪种应用? + +**答:C. 实时聊天系统** + +以下哪个是 Node.js 的创始人? + +**答:B. Ryan Dahl** + +Node.js 中的 "I/O" 主要指什么? + +**答:A. Input/Output(输入 / 输出)** + +Node.js 的 LTS 版本是什么意思?目前最新的 LTS 版本是哪个? + +**答:B. Long Term Support** + +npm 是用来做什么的? + +**答:B. 管理 Node.js 包** + +初始化 Node.js 项目的命令是? + +**答:C. npm init** + +运行 Node.js 程序的命令是? + +**答:B. node app.js** + +package.json 文件主要记录什么信息? + +**答:B. 项目依赖和配置** + +### 简答题 + +什么是 Node.js?请用一句话概括。 + +**答:Node.js 是一个基于 Chrome V8 JavaScript 引擎构建的、用于在服务器端运行 JavaScript 代码的开源跨平台运行时环境。** + +请解释 "非阻塞 I/O" 是什么意思,它有什么优点? + +**答:非阻塞 I/O 指 Node.js 在执行文件读写、网络请求等 I/O 操作时,不会阻塞主线程等待操作完成,而是将操作交由系统内核处理,主线程继续执行其他任务,待 I/O 操作完成后通过回调函数处理结果;优点是能充分利用 CPU 资源,在处理大量并发请求时性能更高,避免了传统阻塞 I/O 因等待导致的资源浪费,适合高并发的 I/O 密集型场景。** + +为什么 Node.js 适合开发实时聊天应用? + +**答:① Node.js 基于非阻塞 I/O 模型,能高效处理大量并发的客户端连接;② 支持 WebSocket 协议,可实现服务器与客户端的双向实时通信;③ 单线程事件循环模型响应速度快,能即时推送聊天消息,满足实时性要求。** + +请列举 Node.js 的 3 个应用场景。 + +**答:① 实时聊天系统(如微信网页版、Discord);② API 接口服务(为前端提供数据接口);③ 前端工程化工具(如 Webpack、Vite、npm)。** + +Node.js 和传统后端语言(如 Java、PHP)相比,有什么优势? + +**答:① 前后端统一使用 JavaScript,降低开发人员的技术栈切换成本;② 非阻塞 I/O 模型处理高并发请求时性能更优,资源占用更少;③ 丰富的 npm 生态,拥有海量第三方包,开发效率高;④ 轻量、跨平台,部署和启动速度快。** + +请解释LTS 版本和 Current 版本有什么区别? + +**答:① LTS(Long Term Support,长期支持版本):注重稳定性和可靠性,提供长达数年的安全更新和维护;② Current (当前版本):包含最新的功能和特性,但更新迭代快,维护周期短(仅 6 个月)。** + +npm 和 Node.js 是什么关系? + +**答:npm(Node Package Manager)是 Node.js 的官方包管理工具。** + +package.json 文件中的 dependencies 和 devDependencies 有什么区别? + +**答:① dependencies:记录项目运行时依赖的包(如业务逻辑中的 axios、express),生产环境必须安装;② devDependencies:记录项目开发时依赖的包(如 webpack、eslint、jest),仅用于开发和测试,生产环境可无需安装。** + +VSCode 有哪些特点让它适合开发 Node.js? + +**答:① 内置 JavaScript/TypeScript 语法支持,代码高亮、智能提示精准;② 丰富的插件生态(如 Node.js Intellisense、ESLint),可增强 Node.js 开发体验;③ 内置终端,可直接执行 node、npm 命令,无需切换工具;④ 支持断点调试,能直接调试 Node.js 程序;⑤ 轻量跨平台,适配 Node.js 的跨平台特性。** + +请描述在 Windows 上安装 Node.js 的步骤。 + +**答:① 打开 Node.js 官网(https://nodejs.org),下载对应 Windows 系统的 LTS 版本安装包(.msi 格式);② 双击安装包,按向导提示进行安装(建议勾选 “Add to PATH” 选项,自动配置环境变量);③ 安装完成后,打开命令提示符(CMD)或 PowerShell,执行`node -v`和`npm -v`命令,若显示版本号则安装成功;④ (可选)若需更换 npm 镜像源,可执行`npm config set registry https://registry.npmmirror.com`提升包下载速度。** + +### 操作题 +#### 第一题 +![20260306Show01](https://qiniu.lhchen.asia//20260306Show01.png) +#### 第二题 +Netflix、PayPal、Trello +#### 第三题 +不会,我会选择Java搭配Spring Boot框架 +- 多线程处理能力:考试系统高并发场景下,Spring Boot 依托 Java 多线程模型可并行处理请求,Node.js 单线程 + 事件循环易因 CPU 密集型操作(如批量阅卷、数据校验)阻塞主线程,并发承载能力受限。 +- 线程安全保障:考试涉及分数计算、权限校验、数据落库等关键操作,Spring Boot 通过锁、线程池、事务管理等原生机制保障线程安全,避免数据错乱;Node.js 单线程无竞态问题,但一旦引入多进程扩展,线程安全管控复杂度陡增,且生态支持远弱于 Java。 +- 事务与数据一致性:考试成绩、答题记录等核心数据需强事务保证,Spring Boot 整合 JDBC/ORM 框架可实现精准的事务回滚与 ACID 特性;Node.js 异步 IO 模型下事务管控需额外封装,对复杂业务场景适配性差。 +- 成熟的企业级生态:考试系统需权限控制(Spring Security)、分布式锁、集群部署等能力,Spring Boot 生态开箱即用;Node.js 在企业级数据安全、并发管控的成熟度和标准化程度远不及 Spring 体系。 +#### 第四题 +![20260306Show02](https://qiniu.lhchen.asia//20260306Show02.png) +#### 第五、六题 + +##### 关键代码 + +```js +let studentName = "罗皓晨"; +let studentId = 2344310246; + +console.log(`姓名:${studentName},学号:${studentId}`) + +const readline = require('readline/promises') +let rl = readline.createInterface({ + input:process.stdin, + output:process.stdout +}); + +async function add() { + let number01 = Number(await rl.question("请输入第一个数:")); + let number02 = Number(await rl.question("请输入第二个数:")); + let number03 = Number(await rl.question("请输入第三个数:")); + console.log(`结果是:${number01+number02+number03}`); +} + +add(); +``` + +##### 效果展示 + +![20260306Show03](https://qiniu.lhchen.asia//20260306Show03.png) + diff --git "a/\347\275\227\347\232\223\346\231\250/20260309-nodejsnpm\345\214\205\347\256\241\347\220\206\345\231\250.md" "b/\347\275\227\347\232\223\346\231\250/20260309-nodejsnpm\345\214\205\347\256\241\347\220\206\345\231\250.md" new file mode 100644 index 0000000000000000000000000000000000000000..97e69e1a87549e9941f124cd8b2d9cf63f707518 --- /dev/null +++ "b/\347\275\227\347\232\223\346\231\250/20260309-nodejsnpm\345\214\205\347\256\241\347\220\206\345\231\250.md" @@ -0,0 +1,94 @@ + + +## 笔记 + +### package.json 核心配置说明 + +| 字段 | 作用 | 注意事项 | +|------|------|----------| +| name | 项目名称 | 必须小写,不能有大写字母 | +| version | 版本号 | 遵循**语义化版本规范**(主版本.次版本.修订版) | +| description | 项目描述 | 简洁说明项目用途 | +| main | 入口文件 | 项目启动/被引用时的入口(默认index.js) | +| scripts | 自定义脚本 | 可通过 `npm run <脚本名>` 执行,如dev、test | +| keywords | 关键词 | 便于npm检索,数组格式 | +| author | 作者 | 可写姓名/邮箱/主页 | +| license | 许可证 | 如MIT(开源)、ISC等 | +| dependencies | 生产依赖 | 项目运行期必须的包(如express、mysql2) | +| devDependencies | 开发依赖 | 仅开发/测试期使用(如nodemon、jest) | + +### 主流包管理工具命令对比 + +| 操作 | npm | yarn | pnpm | +|------|-----|------|------| +| 初始化项目 | `npm init -y` | `yarn init -y` | `pnpm init` | +| 安装生产依赖 | `npm install <包名>` | `yarn add <包名>` | `pnpm add <包名>` | +| 安装开发依赖 | `npm install -D <包名>` | `yarn add <包名> -D` | `pnpm add -D <包名>` | +| 全局安装 | `npm install -g <包名>` | `yarn global add <包名>` | `pnpm add -g <包名>` | +| 卸载依赖 | `npm uninstall <包名>` | `yarn remove <包名>` | `pnpm remove <包名>` | +| 运行自定义脚本 | `npm run <脚本名>` | `yarn <脚本名>` | `pnpm <脚本名>` | +| 查看依赖 | `npm list` | `yarn list` | `pnpm list` | +| 检查更新 | - | `yarn outdated` | `pnpm outdated` | +| 配置镜像 | `npm config set registry <地址>` | `yarn config set registry <地址>` | `pnpm config set registry <地址>` | + +### 工具安装前置命令 +```bash +# 安装yarn +npm install -g yarn + +# 安装pnpm +npm install -g pnpm + +# 国内常用镜像(淘宝源) +npm config set registry https://registry.npmmirror.com/ +yarn config set registry https://registry.npmmirror.com/ +pnpm config set registry https://registry.npmmirror.com/ +``` + +## 作业 + +### 简答题 + +1. 请解释dependencies和devDependencies的区别 + +**答:dependencies(生产依赖)是项目运行阶段必须的依赖包,devDependencies(开发依赖)是仅开发/测试阶段使用的依赖包** + +2. 什么是语义化版本号?请举例说明 "^1.2.3" 的含义 + +**答:1.2.3格式为 `主版本号.次版本号.修订版`(如1.2.3),主版本号是不兼容的API变更(如2.0.0对比1.9.9),次版本号是向后兼容的功能新增(如1.3.0对比1.2.3),修订版是向后兼容的问题修复(如1.2.4对比1.2.3)。`^` 是版本范围标识符,表示兼容最新的次版本和修订版,即安装时会匹配 `1.x.x` 中最新的版本(如1.2.5、1.3.0),但不会升级到2.0.0(主版本号变化)。** + +3. 为什么国内使用npm需要配置镜像源? + +**答:npm的官方仓库服务器位于国外,国内网络访问时速度慢、易超时,甚至出现依赖包下载失败的情况,而国内镜像(如淘宝npmmirror)会同步官方仓库的包到国内服务器,访问速度大幅提升;** + +4. 请描述npm install命令的执行过程 + +**答:解析参数→解析依赖树→缓存 / 下载→安装→执行脚本;** + +5. 全局安装和本地安装有什么区别? + +**答:全局 / 本地安装核心区别:安装路径、作用范围、使用场景不同,本地安装会记录到项目依赖文件,全局安装则为系统级可用。** + +6. yarn和npm相比有什么优势? + +**答:速度更快,版本更稳定,安装更安全,体验更好,扁平化依赖** + +7. pnpm的node_modules结构有什么特点?为什么能节省空间? + +**答:pnpm不采用npm/yarn的扁平化或嵌套结构,而是采用硬链接+符号链接的方式,所有包都存储在全局仓库(~/.pnpm-store),每个版本仅存储一次;** + +### 操作题 + +1. **创建项目**:使用npm init创建一个新项目,添加项目名称为"my-blog",作者为你的名字。 + +2. **安装依赖**:安装express框架作为生产依赖,安装nodemon作为开发依赖。 + +3. **查看信息**:使用npm view命令查看express的最新版本和所有版本。 + +4. **配置脚本**:在package.json中添加一个"dev"脚本,使用nodemon运行index.js。 + +5. **切换镜像**:将npm镜像切换为淘宝镜像,然后安装一个包验证速度。 + +6. **安装yarn**:全局安装yarn,并使用yarn安装一个包体验速度。 + +7. **安装pnpm**:全局安装pnpm,并使用pnpm安装一个包,观察node_modules结构。 \ No newline at end of file diff --git "a/\347\275\227\347\232\223\346\231\250/20260311-nodejs\346\250\241\345\235\227.md" "b/\347\275\227\347\232\223\346\231\250/20260311-nodejs\346\250\241\345\235\227.md" new file mode 100644 index 0000000000000000000000000000000000000000..b3c162a6dd95d475f3919a4115bdbe7aca78089b --- /dev/null +++ "b/\347\275\227\347\232\223\346\231\250/20260311-nodejs\346\250\241\345\235\227.md" @@ -0,0 +1,176 @@ +## 笔记 + +### CommonJS + +#### 目录结构 + +```bash +commonjs-demo/ +├── math.js // 导出模块 +└── main.js // 导入模块 +``` + +#### 导出模块(module.exports) + +```js +// 方式1:导出单个函数(注释掉下面的方式2/3可测试) + module.exports = function(a, b) { + return a + b; + }; + +// 方式2:导出对象(包含多个功能) +module.exports = { + add: (a, b) => a + b, + subtract: (a, b) => a - b, + PI: 3.14159 + }; + +// 方式3:给 exports 添加属性(最常用) +exports.add = (a, b) => a + b; +exports.subtract = (a, b) => a - b; +exports.multiply = (a, b) => a * b; + +// 错误示例(不要这么写,导出无效) + exports = function() { console.log('无效导出'); }; +``` + +#### 导入模块(require) + +```js +// 导入自定义模块(相对路径) +const math = require('./math.js'); // .js 后缀可省略,写成 ./math 也可以 + +// 测试导入结果 +console.log('CommonJS 模块测试:'); +// 如果是方式1(单个函数),直接调用 + console.log('10 + 20 =', math(10, 20)); + +// 如果是方式2/3(多属性),通过对象访问 +console.log('10 + 20 =', math.add(10, 20)); // 输出 30 +console.log('20 - 10 =', math.subtract(20, 10)); // 输出 10 +console.log('PI =', math.PI || '未定义'); // 方式2输出3.14159,方式3输出"未定义" + +// 导入 Node.js 内置模块示例 +const path = require('path'); +console.log('当前文件路径:', path.resolve(__filename)); // 输出当前文件的绝对路径 +``` + +------ + +### ES Modules + +#### 前置说明 + +Node.js 中使用 ES Modules 有两种方式: + +1. 文件后缀改为 `.mjs` +2. 新建 `package.json`,添加 `"type": "module"`(推荐) + +#### 目录结构 + +```bash +esm-demo/ +├── package.json // 配置模块类型 +├── math.mjs // 导出模块(也可写 math.js,配合 package.json) +└── main.mjs // 导入模块 +``` + +#### 配置文件(package.json) + +```js +{ + "type": "module" +} +``` + +#### 导出模块(export) + +```js +// 方式1:命名导出(直接导出) +export const name = "数学工具库"; +export function add(a, b) { + return a + b; +} +export function subtract(a, b) { + return a - b; +} + +// 方式2:批量命名导出 +const multiply = (a, b) => a * b; +const divide = (a, b) => a / b; +export { multiply, divide }; + +// 方式3:默认导出(一个模块只能有一个) +export default function() { + console.log("这是默认导出的函数"); +} +``` + +#### 导入模块(import) + +```js +// 1. 导入命名导出(精准匹配名称) +import { add, subtract, multiply } from './math.mjs'; + +// 2. 命名导出重命名(避免冲突) +import { divide as div } from './math.mjs'; + +// 3. 导入默认导出(自定义名称) +import defaultFunc from './math.mjs'; + +// 4. 导入所有导出(命名空间) +import * as math from './math.mjs'; + +// 测试结果 +console.log('ES Modules 模块测试:'); +console.log('10 + 20 =', add(10, 20)); // 30 +console.log('20 - 10 =', subtract(20, 10)); // 10 +console.log('10 × 20 =', multiply(10, 20)); // 200 +console.log('20 ÷ 10 =', div(20, 10)); // 2 + +// 调用默认导出 +defaultFunc(); // 输出 "这是默认导出的函数" + +// 通过命名空间访问所有导出 +console.log('工具库名称:', math.name); // 数学工具库 +console.log('10 × 5 =', math.multiply(10, 5)); // 50 +math.default(); // 调用默认导出的函数 +``` + +------ + +### 总结 + +1. **CommonJS**:核心用 `module.exports/exports` 导出、`require` 导入,文件后缀 `.js`,Node.js 直接运行,`exports` 不能直接赋值。 +2. **ES Modules**:核心用 `export`(命名)/`export default`(默认)导出、`import` 导入,需配置 `package.json` 或后缀 `.mjs`,命名导出需匹配名称,默认导出可自定义名称。 +3. 运行验证:两种示例均可直接复制到本地,执行对应 `node` 命令即可看到输出结果,直观理解模块的导出和导入逻辑。 + +## 作业 + +### 简答题 + +1. 什么是模块?为什么要使用模块? + +2. 请解释module.exports和exports的区别。 + +3. CommonJS和ES Modules有什么区别? + +4. Node.js加载模块的顺序是怎样的? + +5. 什么是模块作用域?它有什么作用? + +### 操作题 + +1. **创建模块**:创建一个 `stringUtils.js` 模块,导出以下函数: + - `capitalize(str)` - 首字母大写 + - `reverse(str)` - 反转字符串 + - `trim(str)` - 去除两端空格 + +2. **使用模块**:创建 `index.js`,引入并测试 `stringUtils.js` 的所有函数。 + +3. **模块封装**:创建一个 `Person` 类,包含name、age属性和introduce方法,并在另一个文件中使用。 + +4. **模块加载实验**:创建一个有循环引用的模块对,观察Node.js如何处理。 + +5. **ES Modules尝试**(选做):将项目改为使用ES Modules,创建 `.mjs` 文件并测试import/export。 + diff --git "a/\347\275\227\347\232\223\346\231\250/20260312-nodejsCLI.md" "b/\347\275\227\347\232\223\346\231\250/20260312-nodejsCLI.md" new file mode 100644 index 0000000000000000000000000000000000000000..1247d497028d9db3ee30a94471ca85c304670e16 --- /dev/null +++ "b/\347\275\227\347\232\223\346\231\250/20260312-nodejsCLI.md" @@ -0,0 +1,166 @@ +## 笔记 + +### CLI和GUI + +#### CLI(Command-Line Interface) + +**命令行界面** + +- 纯**文字**,靠敲命令操作电脑 / 软件 +- 没有窗口、按钮、图标 +- 例子:Windows 的 CMD、PowerShell、Linux/macOS 终端 + +#### GUI(Graphical User Interface) + +**图形用户界面** + +- 用**图形、窗口、按钮、图标、鼠标**操作 +- 看得见、点得着 +- 例子:Windows 桌面、微信、浏览器、手机界面 + +### 命令行参数(process.argv) + +#### process.argv数组 + +`process.argv` 是 Node.js 中内置的数组,用于获取运行 Node.js 脚本时传入的**命令行参数**,数组默认包含两个固定元素: + +- `process.argv[0]`:Node.js 可执行文件的路径(如 `/usr/local/bin/node`) +- `process.argv[1]`:当前执行的脚本文件路径(如 `./index.js`) +- `process.argv[2]` 及以后:用户手动传入的自定义参数 + +#### 代码示例 +```javascript +// 文件名:argv-demo.js +// 运行命令:node argv-demo.js 张三 20 男 + +// 打印完整的参数数组 +console.log("完整参数数组:", process.argv); + +// 提取用户自定义参数(排除前两个默认参数) +const userArgs = process.argv.slice(2); +console.log("用户传入的参数:", userArgs); // 输出:[ '张三', '20', '男' ] + +// 解构赋值获取具体参数 +const [name, age, gender] = userArgs; +console.log(`姓名:${name},年龄:${age},性别:${gender}`); +``` + +#### 运行结果 +```json +完整参数数组:[ + '/usr/local/bin/node', + '/Users/xxx/argv-demo.js', + '张三', + '20', + '男' +] +用户传入的参数:[ '张三', '20', '男' ] +姓名:张三,年龄:20,性别:男 +``` + +### 文件操作(fs 模块) + +#### 读取文件 + +##### readFileSync方法 + +```js +fs.readFileSync(path[, encoding]) +``` + +- `path`:必填,文件的路径(推荐用 `path.join(__dirname, '文件名')` 确保路径正确) +- `encoding`:可选,文件编码(如 `'utf8'`),不传则返回二进制 `Buffer` 数据 + +##### 示例 + +```js +const fs = require('fs'); +const path = require('path'); + +// 1. 读取文本文件(指定utf8编码,返回字符串) +const readPath = path.join(__dirname, 'test.txt'); +const content = fs.readFileSync(readPath, 'utf8'); +console.log('文件内容:', content); + +// 2. 读取二进制文件(如图片,不传编码,返回Buffer) +const imgPath = path.join(__dirname, 'logo.png'); +const imgBuffer = fs.readFileSync(imgPath); +console.log('图片二进制数据长度:', imgBuffer.length); +``` + +#### 写入文件 + +##### writeFileSync方法 + +```js +fs.writeFileSync(path, data[, options]) +``` + +- `path`:必填,要写入的文件路径 +- `data`:必填,要写入的内容(字符串 / Buffer 都可以) +- `options`:可选,常用 `{ flag: 'w' }`(默认覆盖)或 `{ flag: 'a' }`(追加) + +##### 示例 + +```js +const fs = require('fs'); +const path = require('path'); + +// 1. 覆盖写入文件(默认行为) +const writePath1 = path.join(__dirname, 'output.txt'); +fs.writeFileSync(writePath1, '这是覆盖写入的内容'); +console.log('覆盖写入成功'); + +// 2. 追加写入文件(加 flag: 'a') +fs.writeFileSync(writePath1, '\n这是追加的内容', { flag: 'a' }); +console.log('追加写入成功'); + +// 3. 写入二进制文件(比如复制图片) +const imgBuffer = fs.readFileSync(path.join(__dirname, 'logo.png')); +fs.writeFileSync(path.join(__dirname, 'logo-copy.png'), imgBuffer); +console.log('二进制文件写入成功'); +``` + +------ + +#### 总结 + +**读取**:核心是 `fs.readFileSync(路径, 编码)`,指定 `utf8` 读文本,不传编码读二进制; + +**写入**:核心是 `fs.writeFileSync(路径, 内容, 选项)`,默认覆盖写入,`{ flag: 'a' }` 实现追加。 + +## 作业 + +### 简答题 + +请解释什么是CLI工具?它和GUI有什么区别? + +process.argv返回的数组包含哪些内容? + +请说明fs.readFileSync和fs.readFile的区别。 + +为什么要使用JSON文件存储数据?有什么优缺点? + +如何让开发的CLI工具可以全局使用? + +### 操作题 + +**完善待办工具**:完成本任务中的todo.js开发,并测试所有功能。 + +**扩展功能**:为待办工具添加"优先级"功能,支持高/中/低优先级。 + +**笔记工具**:开发一个简单的笔记CLI工具,支持: + - `add <标题> <内容>` - 添加笔记 + - `list` - 列出所有笔记 + - `search <关键词>` - 搜索笔记 + +**计算器工具**:开发一个命令行计算器,支持: + - `add ` - 加法 + - `sub ` - 减法 + - `mul ` - 乘法 + - `div ` - 除法 + +**文件处理工具**:开发一个文件处理工具,支持: + - `count <文件名>` - 统计文件行数 + - `upper <文件名>` - 转为大写 + - `lower <文件名>` - 转为小写 \ No newline at end of file diff --git "a/\347\275\227\347\232\223\346\231\250/20260313-nodejs\347\225\252\345\244\226\347\257\207\344\271\213\350\200\201\350\203\241\344\270\215\345\234\250\346\225\231\345\256\244\357\274\214\344\270\200\344\270\252\344\272\272\345\276\210\345\257\202\345\257\236.md" "b/\347\275\227\347\232\223\346\231\250/20260313-nodejs\347\225\252\345\244\226\347\257\207\344\271\213\350\200\201\350\203\241\344\270\215\345\234\250\346\225\231\345\256\244\357\274\214\344\270\200\344\270\252\344\272\272\345\276\210\345\257\202\345\257\236.md" new file mode 100644 index 0000000000000000000000000000000000000000..4c995803c1050e82c6b34f7f547bd6546e09a91c --- /dev/null +++ "b/\347\275\227\347\232\223\346\231\250/20260313-nodejs\347\225\252\345\244\226\347\257\207\344\271\213\350\200\201\350\203\241\344\270\215\345\234\250\346\225\231\345\256\244\357\274\214\344\270\200\344\270\252\344\272\272\345\276\210\345\257\202\345\257\236.md" @@ -0,0 +1,7 @@ +## 笔记 + +…… + +## 作业 + +…… \ No newline at end of file