单元1 · Node.js 环境与基础入门
安装 Node、npm、console 输出、变量、let/const 与模板字符串
- 运行方式:node 文件名.js 执行脚本;npm 管理依赖。
- 声明变量:let 可改、const 不可改;var 有函数作用域问题应少用。
- 模板字符串:反引号 + ${} 内嵌表达式,支持多行。
实训1.1 Hello World 与 Node 运行
编写第一个 Node.js 程序,用 console.log 输出一行问候语,并说明运行方式。
Node.js 通过 node 文件名.js 运行脚本;console.log 在终端输出内容。
console.log("Hello, Node.js!");
console.log("当前版本:" + process.version);
实训1.2 let 与 const 声明
用 let 声明可修改变量 age=21,用 const 声明常量 NAME='Node',分别输出并尝试说明差异。
let 声明的变量可重新赋值;const 声明常量不可重新赋值(对象属性仍可改)。
let age = 21;
const NAME = "Node";
age = 22;
console.log("age =", age);
console.log("NAME =", NAME);
// NAME = "JS"; // 报错:常量不可重新赋值
实训1.3 模板字符串与解构
使用模板字符串拼接变量,并用解构语法从数组和对象中取值输出。
模板字符串用反引号包裹、${} 嵌入表达式;解构用 [] 和 {} 提取数组与对象成员。
const name = "Alice";
const score = 92;
console.log(`姓名:${name},成绩:${score} 分`);
const [a, b] = [10, 20];
console.log("a + b =", a + b);
const { title, author } = { title: "Node 实战", author: "Marvis" };
console.log(`《${title}》作者:${author}`);
实训1.4 npm 与 package.json
说明 npm init 生成 package.json 的作用,并手写一个最小 package.json 示例。
package.json 描述项目名称、版本、入口与依赖;npm install 按它安装依赖。
{
"name": "my-node-app",
"version": "1.0.0",
"description": "Node.js 入门示例",
"main": "index.js",
"scripts": {
"start": "node index.js"
},
"dependencies": {
"express": "^4.19.0"
}
}
单元2 · 数据类型与运算符
原始类型、typeof、算术/比较/逻辑运算符、类型转换
- 原始类型:string/number/boolean/null/undefined/symbol/bigint。
- 严格相等:=== 比较值与类型,== 会做隐式转换应避免。
- 转换:Number()/String()/Boolean() 显式转换。
实训2.1 基础类型与 typeof
声明字符串、数字、布尔、null、undefined 五种值,用 typeof 分别输出类型。
JS 原始类型有 string/number/boolean/null/undefined/symbol/bigint;typeof null 返回 object。
const s = "hello";
const n = 42;
const b = true;
const nl = null;
let u;
console.log(typeof s, typeof n, typeof b, typeof nl, typeof u);
实训2.2 算术运算与求余
给定 17 和 5,输出和、差、积、商、余数与幂。
+ - * / % 分别对应加减乘除取余;** 是幂运算。
const a = 17, b = 5;
console.log("和:", a + b);
console.log("差:", a - b);
console.log("积:", a * b);
console.log("商:", a / b);
console.log("余数:", a % b);
console.log("a 的 b 次方:", a ** b);
实训2.3 比较与逻辑运算
a=8、b=12,输出 a>b、a!==b、a<10 && b>10、!(a===8) 的结果。
=== 严格相等、!== 严格不等;&& 与、|| 或、! 非。
const a = 8, b = 12;
console.log("a > b:", a > b);
console.log("a !== b:", a !== b);
console.log("a<10 && b>10:", a < 10 && b > 10);
console.log("!(a === 8):", !(a === 8));
实训2.4 类型转换实战
把字符串 '42' 转为数字加 8,再转回字符串拼接,输出结果与类型。
Number() 转数字、String() 转字符串;+ 号遇到字符串会做拼接。
const s = "42";
const n = Number(s) + 8;
const text = String(n);
console.log("结果:", text, ",类型:", typeof text);
console.log("隐式转换 '5' + 3 =", "5" + 3, ",'5' * 3 =", "5" * 3);
单元3 · 流程控制:分支结构
if/else if/else、switch、三元表达式
- if/else:逐级判断,条件可以是任意表达式。
- switch:case 匹配 + break;default 兜底。
- 三元:条件 ? 真 : 假;?? 空值合并。
实训3.1 if 判断成绩等级
成绩 score=85,输出等级:>=90 优秀、>=80 良好、>=60 及格、否则不及格。
用 if / else if / else 逐级判断,注意边界条件。
const score = 85;
if (score >= 90) {
console.log("优秀");
} else if (score >= 80) {
console.log("良好");
} else if (score >= 60) {
console.log("及格");
} else {
console.log("不及格");
}
实训3.2 switch 判断星期
用 switch 把数字 1-7 映射为星期一至星期日,输入 4 输出对应星期。
switch 匹配 case;注意每支 case 用 break 跳出,default 兜底。
const day = 4;
switch (day) {
case 1: console.log("星期一"); break;
case 2: console.log("星期二"); break;
case 3: console.log("星期三"); break;
case 4: console.log("星期四"); break;
case 5: console.log("星期五"); break;
case 6: console.log("星期六"); break;
case 7: console.log("星期日"); break;
default: console.log("无效输入");
}
实训3.3 三元表达式与空值合并
判断 n=15 的奇偶并输出;再演示 ?? 空值合并运算符的用法。
条件 ? 真值 : 假值;?? 在左值为 null/undefined 时取右值。
const n = 15;
console.log(n % 2 === 0 ? "偶数" : "奇数");
const maybeNull = null;
const value = maybeNull ?? "默认值";
console.log("空值合并结果:", value);
const username = "admin";
console.log(username ? `欢迎,${username}` : "请登录");
实训3.4 多条件评分函数
编写函数 getGrade(score) 返回等级,测试 95、72、120 三个输入。
先校验范围再分级;120 属于非法输入返回提示。
function getGrade(score) {
if (score < 0 || score > 100) return "非法分数";
if (score >= 90) return "优秀";
if (score >= 60) return "及格";
return "不及格";
}
console.log("95 ->", getGrade(95));
console.log("72 ->", getGrade(72));
console.log("120 ->", getGrade(120));
单元4 · 循环结构
for、while、break/continue、数组遍历
- for:标准三要素循环;while 适合未知次数。
- 控制:break 终止、continue 跳过。
- 遍历:forEach/map/filter/reduce 函数式遍历。
实训4.1 for 求和 1 到 100
用 for 循环计算 1+2+...+100 的和并输出。
标准 for 三要素:初始化、条件、步进;累加器初始为 0。
let sum = 0;
for (let i = 1; i <= 100; i++) {
sum += i;
}
console.log("1 到 100 的和:", sum);
实训4.2 打印乘法表
输出 9x9 乘法表,每行一个乘数,格式如 1x1=1 2x1=2。
嵌套两层 for;内层次数随外层 i 变化;用制表符或空格对齐。
for (let i = 1; i <= 9; i++) {
let row = "";
for (let j = 1; j <= i; j++) {
row += `${j}x${i}=${i * j} `;
}
console.log(row);
}
实训4.3 break 与 continue
输出 1 到 20 中能被 3 整除的数;遇到 15 用 break 提前结束。
continue 跳过当前迭代,break 终止整个循环。
for (let i = 1; i <= 20; i++) {
if (i === 15) break;
if (i % 3 !== 0) continue;
console.log(i);
}
实训4.4 forEach 与 reduce 遍历
给定 nums=[3,8,15,22,7],分别用 forEach 累加求和、用 reduce 求乘积。
forEach 遍历副作用操作;reduce 折叠数组为单值,需给初始值。
const nums = [3, 8, 15, 22, 7];
let sum = 0;
nums.forEach(v => { sum += v; });
console.log("forEach 求和:", sum);
const product = nums.reduce((acc, v) => acc * v, 1);
console.log("reduce 求积:", product);
单元5 · 函数与作用域
函数声明、箭头函数、默认参数、闭包
- 函数声明:function 有提升;箭头函数更简洁。
- 默认/剩余:默认参数 = 值;...args 收集剩余参数。
- 闭包:内层函数引用外层变量并保持状态。
实训5.1 定义求和函数
定义函数 add(a, b) 返回两数之和,用函数声明与箭头函数两种写法。
function 声明有提升;箭头函数更简洁,适合回调场景。
function add(a, b) {
return a + b;
}
const addArrow = (a, b) => a + b;
console.log("函数声明:", add(10, 20));
console.log("箭头函数:", addArrow(10, 20));
实训5.2 默认参数与剩余参数
定义 greet(name, greeting='你好') 带默认参数;定义 sumAll(...nums) 接收任意个数求和。
默认参数在未传时生效;剩余参数 ...nums 收集为数组。
function greet(name, greeting = "你好") {
return `${greeting},${name}!`;
}
console.log(greet("小明"));
console.log(greet("小红", "早上好"));
function sumAll(...nums) {
return nums.reduce((acc, v) => acc + v, 0);
}
console.log("sumAll(1,2,3) =", sumAll(1, 2, 3));
console.log("sumAll(1,2,3,4,5) =", sumAll(1, 2, 3, 4, 5));
实训5.3 判断质数函数
定义 isPrime(n) 判断质数,输出 29 和 30 的结果。
质数大于 1 且只能被 1 和自身整除;循环到平方根即可。
function isPrime(n) {
if (n < 2) return false;
for (let i = 2; i * i <= n; i++) {
if (n % i === 0) return false;
}
return true;
}
console.log("29 是质数:", isPrime(29));
console.log("30 是质数:", isPrime(30));
实训5.4 闭包计数器
编写 makeCounter() 返回一个函数,每次调用计数加一并返回当前值,验证两次独立计数器互不影响。
闭包让内层函数记住外层变量;每次调用 makeCounter 生成独立作用域。
function makeCounter() {
let count = 0;
return function () {
count++;
return count;
};
}
const c1 = makeCounter();
const c2 = makeCounter();
console.log("c1:", c1(), c1(), c1());
console.log("c2:", c2());
单元6 · 数组与字符串方法
数组增删改查、map/filter/sort、字符串常用方法
- 增删:push/pop 尾部,unshift/shift 头部。
- 转换:map 映射、filter 过滤、sort 排序。
- 字符串:trim/split/replace/toUpperCase 等常用方法。
实训6.1 数组基本操作
创建水果数组,用 push/unshift 添加、pop/shift 删除、indexOf 查找并输出结果。
push/pop 操作尾部,unshift/shift 操作头部;indexOf 返回索引或 -1。
const fruits = ["苹果", "香蕉"];
fruits.push("橙子");
fruits.unshift("葡萄");
console.log("添加后:", fruits);
fruits.pop();
fruits.shift();
console.log("删除后:", fruits);
console.log("香蕉的索引:", fruits.indexOf("香蕉"));
实训6.2 map 与 filter 转换
给定成绩数组 [55, 90, 72, 88, 45],用 filter 筛选及格者,用 map 生成带等级的字符串。
filter 返回满足条件的元素;map 将每个元素映射为新值。
const scores = [55, 90, 72, 88, 45];
const passed = scores.filter(s => s >= 60);
console.log("及格成绩:", passed);
const graded = scores.map(s => `${s} 分(${s >= 60 ? "及格" : "不及格"})`);
console.log(graded);
实训6.3 字符串处理
对字符串 ' Hello, Node.js ' 去除首尾空格、转大写、替换、按逗号拆分并输出。
trim/toUpperCase/replace/split 是常用字符串方法。
const s = " Hello, Node.js ";
console.log("trim:", s.trim());
console.log("大写:", s.trim().toUpperCase());
console.log("替换:", s.trim().replace("Node.js", "JavaScript"));
console.log("拆分:", s.trim().split(","));
实训6.4 排序与去重
对数组 [3, 1, 4, 1, 5, 9, 2, 6] 去重后升序输出,再用 join 拼接为字符串。
Set 去重;sort((a,b)=>a-b) 升序;join 拼接数组为字符串。
const nums = [3, 1, 4, 1, 5, 9, 2, 6];
const unique = [...new Set(nums)];
unique.sort((a, b) => a - b);
console.log("去重排序:", unique);
console.log("拼接:", unique.join("-"));
单元7 · 对象与 JSON
对象创建、属性访问、遍历、JSON 序列化
- 对象:{} 创建;点号/方括号访问。
- 遍历:for...in、Object.keys/values/entries。
- JSON:stringify 序列化、parse 解析。
实训7.1 对象创建与访问
创建学生对象(姓名、年龄、成绩),用点号和方括号访问属性,并添加新属性。
点号访问静态属性;方括号可用变量或含特殊字符的键名。
const student = {
name: "小明",
age: 18,
score: 92.5
};
console.log("姓名:", student.name);
console.log("年龄:", student["age"]);
student.city = "广州";
const key = "score";
console.log("成绩:", student[key]);
实训7.2 对象遍历
用 for...in 遍历对象属性,用 Object.keys/values/entries 分别输出。
for...in 遍历键;Object.keys/values/entries 返回数组便于处理。
const book = { title: "Node 实战", price: 59, author: "Marvis" };
for (const key in book) {
console.log(key, "=", book[key]);
}
console.log("keys:", Object.keys(book));
console.log("values:", Object.values(book));
console.log("entries:", Object.entries(book));
实训7.3 JSON 序列化与解析
把对象序列化为 JSON 字符串输出,再解析回对象并读取字段。
JSON.stringify 序列化;JSON.parse 反序列化。
const user = { id: 1, name: "Alice", tags: ["admin", "dev"] };
const json = JSON.stringify(user);
console.log("JSON 字符串:", json);
const back = JSON.parse(json);
console.log("解析回对象 name:", back.name);
console.log("tags 长度:", back.tags.length);
实训7.4 对象数组统计
给定 3 本书的对象数组,用 reduce 求总价、用 sort 按价格降序输出书名。
reduce 累加 price 字段;sort 按 price 降序。
const books = [
{ title: "Node 实战", price: 59 },
{ title: "JavaScript 权威指南", price: 128 },
{ title: "深入浅出 Node.js", price: 79 }
];
const total = books.reduce((acc, b) => acc + b.price, 0);
console.log("总价:", total);
books.sort((a, b) => b.price - a.price);
console.log("最贵的书:", books[0].title);
单元8 · 模块系统
CommonJS 导出/导入、ESM、内置模块 require
- CommonJS:module.exports 导出、require 导入。
- ESM:export/import 静态语法,.mjs 扩展名。
- 内置模块:os/path/fs 开箱即用。
实训8.1 CommonJS 模块导出
编写 math.js 导出 add、multiply 两个函数,在 main.js 中导入并调用。
module.exports 导出对象;require 导入并解构使用。
// math.js
function add(a, b) { return a + b; }
function multiply(a, b) { return a * b; }
module.exports = { add, multiply };
// main.js
const { add, multiply } = require("./math");
console.log("add(3,4) =", add(3, 4));
console.log("multiply(3,4) =", multiply(3, 4));
实训8.2 ESM 模块语法
用 export 默认导出与命名导出,import 时混合导入。
export default 默认导出;export 命名导出;import 可混合。
// utils.mjs
export default function greet(name) {
return `Hello, ${name}!`;
}
export const VERSION = "1.0.0";
// app.mjs
import greet, { VERSION } from "./utils.mjs";
console.log(greet("Node"));
console.log("版本:", VERSION);
实训8.3 内置模块 os 与 path
使用 os 模块输出系统平台与 CPU 核数,用 path 模块拼接路径并输出扩展名。
os.platform/os.cpus 获取系统信息;path.join 拼接、path.extname 取扩展名。
const os = require("os");
const path = require("path");
console.log("平台:", os.platform());
console.log("CPU 核数:", os.cpus().length);
console.log("内存(GB):", (os.totalmem() / 1024 ** 3).toFixed(1));
const p = path.join(__dirname, "docs", "readme.md");
console.log("拼接路径:", p);
console.log("扩展名:", path.extname(p));
实训8.4 fs 文件读写
用 fs 模块同步写入 data.txt,再读取内容并输出。
fs.writeFileSync 写入;fs.readFileSync 读取需指定 utf-8 编码。
const fs = require("fs");
const file = "data.txt";
fs.writeFileSync(file, "Hello Node.js File System
第二行内容");
const content = fs.readFileSync(file, "utf-8");
console.log("文件内容:");
console.log(content);
console.log("文件大小:", fs.statSync(file).size, "字节");
单元9 · 异步编程
回调、Promise、async/await、事件循环
- Promise:resolve/reject、then/catch 链式处理。
- async/await:await 暂停直到 Promise 完成。
- 并发:Promise.all 并发等待;try/catch/finally 处理。
实训9.1 Promise 基础
创建 Promise 模拟延迟 1 秒返回成功,用 then/catch 处理结果与错误。
Promise 构造器接收 resolve/reject;then 处理成功、catch 处理失败。
const delay = (ms) =>
new Promise((resolve) => setTimeout(resolve, ms));
delay(1000)
.then(() => "任务完成")
.then((msg) => console.log(msg))
.catch((err) => console.error("出错:", err));
实训9.2 async/await 语法
用 async 函数和 await 顺序执行两个延迟任务并输出结果。
await 暂停 async 函数直到 Promise 完成;try/catch 捕获异常。
const delay = (ms, val) =>
new Promise((resolve) => setTimeout(() => resolve(val), ms));
async function main() {
const first = await delay(500, "第一步");
console.log(first);
const second = await delay(300, "第二步");
console.log(second);
console.log("全部完成");
}
main().catch((err) => console.error(err));
实训9.3 Promise.all 并发
并发执行两个任务,用 Promise.all 等全部完成后汇总输出。
Promise.all 接收 Promise 数组,全部成功才 resolve,结果按序返回。
const delay = (ms, val) =>
new Promise((resolve) => setTimeout(() => resolve(val), ms));
async function main() {
const results = await Promise.all([
delay(600, "任务A"),
delay(400, "任务B")
]);
console.log("并发结果:", results.join(" + "));
}
main();
实训9.4 错误处理与 finally
模拟可能失败的 Promise(随机失败),用 try/catch/finally 处理。
try 中 await;catch 捕获错误;finally 无论成败都执行。
const risky = (ok) =>
new Promise((resolve, reject) =>
ok ? resolve("成功") : reject(new Error("模拟失败"))
);
async function run(ok) {
try {
const result = await risky(ok);
console.log("结果:", result);
} catch (err) {
console.error("错误:", err.message);
} finally {
console.log("清理资源(总是执行)");
}
}
run(true);
run(false);
单元10 · HTTP 与 Web 基础
http 模块、路由、Express 基础
- http 模块:createServer + listen 搭建服务器。
- 路由:req.url 分发路径,404 兜底。
- Express:app.get/res.json 快速构建 API。
实训10.1 原生 http 服务器
用 http 模块创建服务器,监听 3000 端口,根路径返回 Hello。
http.createServer 处理请求;res.end 返回响应;listen 启动监听。
const http = require("http");
const server = http.createServer((req, res) => {
res.writeHead(200, { "Content-Type": "text/plain; charset=utf-8" });
res.end("Hello, HTTP Server!");
});
server.listen(3000, () => {
console.log("服务器已启动:http://localhost:3000");
});
实训10.2 HTTP 路由分发
根据 URL 路径分发:/ 返回首页、/about 返回关于页、其它返回 404。
req.url 判断路径;不同路径返回不同内容与状态码。
const http = require("http");
const server = http.createServer((req, res) => {
const url = req.url;
res.writeHead(200, { "Content-Type": "text/plain; charset=utf-8" });
if (url === "/") {
res.end("首页");
} else if (url === "/about") {
res.end("关于我们");
} else {
res.writeHead(404);
res.end("404 Not Found");
}
});
server.listen(3000);
实训10.3 解析查询参数
用 URL 模块解析 /search?q=node&page=2 的查询参数并输出。
new URL(req.url, 基础地址) 后读取 searchParams。
const http = require("http");
const server = http.createServer((req, res) => {
const url = new URL(req.url, "http://localhost:3000");
const q = url.searchParams.get("q");
const page = url.searchParams.get("page");
res.writeHead(200, { "Content-Type": "text/plain; charset=utf-8" });
res.end(`搜索词:${q},页码:${page}`);
});
server.listen(3000);
实训10.4 Express 快速搭建
用 Express 创建应用:GET / 返回 JSON,GET /api/users 返回用户列表。
express() 创建应用;app.get 定义路由;res.json 返回 JSON。
const express = require("express");
const app = express();
const users = [
{ id: 1, name: "Alice" },
{ id: 2, name: "Bob" }
];
app.get("/", (req, res) => {
res.json({ message: "欢迎使用 Express" });
});
app.get("/api/users", (req, res) => {
res.json(users);
});
app.listen(3000, () => console.log("Express 运行于 3000 端口"));
单元11 · 文件系统与流
fs 异步读写、目录操作、流处理
- fs.promises:Promise 版文件 API,配合 await。
- 目录:mkdir/readdir/stat 管理目录。
- 流:createReadStream + pipe 高效处理大文件。
实训11.1 异步文件读写
用 fs.promises 异步写入并读取文件,输出文件内容。
fs.promises 提供 Promise 版 API;配合 async/await 使用。
const fs = require("fs").promises;
async function main() {
await fs.writeFile("async.txt", "异步写入的内容");
const data = await fs.readFile("async.txt", "utf-8");
console.log("读取到:", data);
}
main().catch(console.error);
实训11.2 目录操作
用 fs 创建目录、读取目录列表、判断是否为文件。
mkdir 创建目录;readdir 读取目录;stat 判断类型。
const fs = require("fs");
if (!fs.existsSync("mydir")) {
fs.mkdirSync("mydir");
}
fs.writeFileSync("mydir/a.txt", "A");
fs.writeFileSync("mydir/b.txt", "B");
const items = fs.readdirSync("mydir");
items.forEach((name) => {
const stat = fs.statSync(`mydir/${name}`);
console.log(name, stat.isFile() ? "文件" : "目录");
});
实训11.3 读取大文件流
用 createReadStream 以流方式读取文件,统计行数并输出。
流式读取逐块处理,不占满内存;监听 data 事件累加。
const fs = require("fs");
const content = Array.from({ length: 1000 }, (_, i) => `第 ${i + 1} 行`).join("\n");
fs.writeFileSync("big.txt", content);
let lines = 0;
const rs = fs.createReadStream("big.txt", { encoding: "utf-8" });
rs.on("data", (chunk) => {
lines += chunk.split("\n").length - 1;
});
rs.on("end", () => {
console.log("总行数:", lines);
});
实训11.4 复制文件(管道)
用 pipe 把源文件内容流式写入目标文件,验证复制结果。
readStream.pipe(writeStream) 自动处理背压与数据流动。
const fs = require("fs");
fs.writeFileSync("source.txt", "使用流复制的内容");
const rs = fs.createReadStream("source.txt");
const ws = fs.createWriteStream("copy.txt");
rs.pipe(ws);
ws.on("finish", () => {
console.log("复制完成:", fs.readFileSync("copy.txt", "utf-8"));
});
单元12 · 综合项目实训
综合运用所学知识完成 CLI 与 Web 任务
- 综合应用:数组、对象、模块、异步、HTTP 组合使用。
- 工程化:函数封装、错误处理、路径处理贯穿全程。
实训12.1 命令行待办清单
实现简易待办管理:数组存储任务,支持添加、列出、删除(按序号)、标记完成。
用函数封装操作;readline 或预置命令模拟交互;数组 splice 删除。
let todos = [];
let nextId = 1;
function add(title) {
todos.push({ id: nextId++, title, done: false });
}
function list() {
todos.forEach((t) =>
console.log(`[${t.done ? "✓" : " "}] ${t.id}. ${t.title}`)
);
}
function remove(id) {
const idx = todos.findIndex((t) => t.id === id);
if (idx !== -1) todos.splice(idx, 1);
}
function toggle(id) {
const t = todos.find((x) => x.id === id);
if (t) t.done = !t.done;
}
add("学习 Node.js");
add("完成实训题");
add("复习异步编程");
toggle(1);
remove(2);
list();
实训12.2 词频统计器
给定文本字符串,统计每个单词出现次数,输出出现最多的词。
split 拆分单词;Map 统计频次;遍历找最大值。
const text = "node is fast node is simple node is fun";
const words = text.toLowerCase().split(" ");
const freq = new Map();
for (const w of words) {
freq.set(w, (freq.get(w) || 0) + 1);
}
let maxWord = "", maxCount = 0;
for (const [w, c] of freq) {
if (c > maxCount) { maxWord = w; maxCount = c; }
}
console.log("词频:", Object.fromEntries(freq));
console.log("出现最多:", maxWord, ",次数:", maxCount);
实训12.3 文件备份脚本
把指定目录下所有 .txt 文件备份到 backup 目录,文件名加时间戳。
readdir 遍历目录;filter 筛选扩展名;copyFileSync 复制;时间戳拼名。
const fs = require("fs");
const path = require("path");
const srcDir = "docs";
const backupDir = "backup";
if (!fs.existsSync(srcDir)) fs.mkdirSync(srcDir);
fs.writeFileSync(path.join(srcDir, "a.txt"), "文档A");
fs.writeFileSync(path.join(srcDir, "b.md"), "文档B");
fs.writeFileSync(path.join(srcDir, "c.txt"), "文档C");
if (!fs.existsSync(backupDir)) fs.mkdirSync(backupDir);
const stamp = new Date().toISOString().slice(0, 10).replace(/-/g, "");
const files = fs.readdirSync(srcDir).filter((f) => f.endsWith(".txt"));
files.forEach((f) => {
const dest = path.join(backupDir, `${stamp}_${f}`);
fs.copyFileSync(path.join(srcDir, f), dest);
console.log("已备份:", dest);
});
实训12.4 简易 HTTP 成绩 API
用原生 http 实现 /api/grade?score=85 返回 JSON 等级结果,含参数校验。
解析查询参数;封装评级逻辑;非法输入返回 400 状态码。
const http = require("http");
const server = http.createServer((req, res) => {
if (!req.url.startsWith("/api/grade")) {
res.writeHead(404, { "Content-Type": "application/json" });
return res.end(JSON.stringify({ error: "Not Found" }));
}
const url = new URL(req.url, "http://localhost:3000");
const score = Number(url.searchParams.get("score"));
if (Number.isNaN(score) || score < 0 || score > 100) {
res.writeHead(400, { "Content-Type": "application/json" });
return res.end(JSON.stringify({ error: "非法分数" }));
}
const grade = score >= 90 ? "优秀" : score >= 60 ? "及格" : "不及格";
res.writeHead(200, { "Content-Type": "application/json" });
res.end(JSON.stringify({ score, grade }));
});
server.listen(3000);