Node.js 开发指南 / 第 3 章 · Hello World
第 3 章 · Hello World
3.1 第一个 Node.js 程序
创建项目目录
mkdir hello-node
cd hello-node
npm init -y
npm init -y 会生成默认的 package.json:
{
"name": "hello-node",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
Hello World 脚本
// index.js
const http = require('http');
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
res.end('Hello, World!\n');
});
const PORT = 3000;
server.listen(PORT, () => {
console.log(`服务器运行在 http://localhost:${PORT}/`);
});
运行并测试:
node index.js
# 服务器运行在 http://localhost:3000/
# 另一个终端
curl http://localhost:3000
# Hello, World!
HTTP 服务器分解
请求 → http.createServer(回调) → req(请求对象) → res(响应对象) → 响应
↓
res.writeHead(状态码, 头信息)
res.end(响应体)
3.2 Node.js REPL
REPL(Read-Eval-Print-Loop)是 Node.js 内置的交互式运行环境。
启动 REPL
# 直接输入 node 进入 REPL
node
# Welcome to Node.js v22.12.0.
# Type ".help" for more information.
>
REPL 基本操作
> 1 + 1
2
> const name = 'Node.js'
undefined
> `Hello, ${name}!`
'Hello, Node.js!'
> [1, 2, 3].map(x => x * 2)
[ 2, 4, 6 ]
> { a: 1, b: 2 }
{ a: 1, b: 2 }
> .help
.break Sometimes you get stuck, this gets you out
.clear Alias for .break
.editor Enter editor mode
.exit Exit the repl
.help Print this help
.load Load JS file into REPL session
.save Save all evaluated commands in this REPL session to a file
使用下划线 _
> 2 + 3
5
> _ + 10
15
多行输入
> function greet(name) {
... return `Hello, ${name}!`;
... }
undefined
> greet('World')
'Hello, World!'
REPL 中加载模块
> const os = require('os')
undefined
> os.platform()
'linux'
> os.cpus().length
8
使用 .editor 模式
> .editor
// 进入编辑器模式,可以输入多行代码
// 按 Ctrl+D 执行,Ctrl+C 取消
function fibonacci(n) {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
fibonacci(10);
// 55
使用 .save 和 .load
> .save session.js // 保存当前会话到文件
> .load session.js // 加载文件中的命令
3.3 脚本运行方式
基本运行
# 运行脚本文件
node app.js
# 运行并传递参数
node app.js arg1 arg2
# 运行并设置环境变量
NODE_ENV=production node app.js
# 检查语法而不执行
node --check app.js
# 运行并显示弃用警告
node --throw-deprecation app.js
读取命令行参数
// args.js
// process.argv 包含命令行参数
// [0] = node 可执行文件路径
// [1] = 脚本文件路径
// [2+] = 用户传递的参数
console.log('原始参数:', process.argv);
// 使用 parseArgs(Node.js 18.3+)
const { parseArgs } = require('node:util');
const options = {
name: { type: 'string', short: 'n' },
verbose: { type: 'boolean', short: 'v' },
port: { type: 'string', short: 'p', default: '3000' },
};
const { values } = parseArgs({ options });
console.log('解析后的参数:', values);
node args.js --name "Node.js" --verbose -p 8080
# 原始参数: [
# '/usr/local/bin/node',
# '/home/user/hello-node/args.js',
# '--name', 'Node.js',
# '--verbose',
# '-p', '8080'
# ]
# 解析后的参数: { name: 'Node.js', verbose: true, port: '8080' }
使用 npm scripts
{
"name": "hello-node",
"scripts": {
"start": "node index.js",
"dev": "node --watch index.js",
"debug": "node --inspect index.js",
"check": "node --check index.js",
"test": "node --test test.js"
}
}
npm start # 运行 start 脚本
npm run dev # 运行 dev 脚本(文件变更自动重启)
npm run debug # 启动调试模式
npm test # 运行测试
node --watch 模式
Node.js 18+ 内置文件监听功能,文件变更时自动重启:
# 监听当前目录下的文件变更
node --watch index.js
# 可以在 npm scripts 中使用
npm run dev
3.4 globalThis 与全局对象
// 全局对象
console.log(globalThis === global); // true (Node.js)
console.log(globalThis === globalThis); // true (所有环境)
// 常用全局对象/函数
console.log('=== 常用全局对象 ===');
console.log(typeof setTimeout); // function
console.log(typeof setInterval); // function
console.log(typeof setImmediate); // function (Node.js 特有)
console.log(typeof console); // object
console.log(typeof process); // object
console.log(typeof Buffer); // function
console.log(typeof __dirname); // string (CJS 模块)
console.log(typeof __filename); // string (CJS 模块)
process 对象
// 进程信息
console.log('进程 ID:', process.pid);
console.log('父进程 ID:', process.ppid);
console.log('Node.js 版本:', process.version);
console.log('平台:', process.platform);
console.log('架构:', process.arch);
console.log('当前工作目录:', process.cwd());
console.log('运行时间:', process.uptime(), '秒');
console.log('内存使用:', process.memoryUsage());
// 环境变量
console.log('NODE_ENV:', process.env.NODE_ENV || '未设置');
console.log('HOME:', process.env.HOME || process.env.USERPROFILE);
// 退出进程
// process.exit(0); // 正常退出
// process.exit(1); // 异常退出
定时器
// setTimeout — 延迟执行
setTimeout(() => {
console.log('1 秒后执行');
}, 1000);
// setInterval — 周期执行
let count = 0;
const timer = setInterval(() => {
count++;
console.log(`第 ${count} 次执行`);
if (count >= 3) {
clearInterval(timer);
console.log('已停止');
}
}, 1000);
// setImmediate — 在当前事件循环结束后立即执行
setImmediate(() => {
console.log('立即执行(在 I/O 回调之后)');
});
// Node.js 特有的高精度定时器
const { setTimeout: setDelay } = require('timers/promises');
async function main() {
console.log('开始');
await setDelay(1000);
console.log('1 秒后');
await setDelay(500);
console.log('1.5 秒后');
}
main();
3.5 控制台输出与格式化
// 基本输出
console.log('普通日志');
console.info('信息日志');
console.warn('警告日志');
console.error('错误日志');
// 格式化输出
console.log('字符串: %s, 数字: %d, JSON: %j', 'hello', 42, { a: 1 });
// 使用模板字符串(推荐)
const user = 'Alice';
const score = 95.6;
console.log(`${user} 的分数: ${score.toFixed(1)}`);
// 计时
console.time('操作');
// 模拟耗时操作
let sum = 0;
for (let i = 0; i < 1000000; i++) sum += i;
console.timeEnd('操作'); // 操作: 3.456ms
// 堆栈跟踪
console.trace('调试信息');
// 表格输出
const data = [
{ name: 'Alice', age: 30, city: 'Beijing' },
{ name: 'Bob', age: 25, city: 'Shanghai' },
{ name: 'Charlie', age: 35, city: 'Guangzhou' },
];
console.table(data);
// 分组输出
console.group('用户信息');
console.log('姓名: Alice');
console.log('年龄: 30');
console.group('地址');
console.log('城市: Beijing');
console.log('区: Haidian');
console.groupEnd();
console.groupEnd();
// 断言
console.assert(1 === 1, '这不会输出'); // 通过
console.assert(1 === 2, '1 不等于 2'); // 输出: Assertion failed: 1 不等于 2
清理终端
// 跨平台清屏
const clear = () => {
process.stdout.write(
process.platform === 'win32' ? '\x1Bc' : '\x1B[2J\x1B[0f'
);
};
clear();
console.log('终端已清屏');
3.6 package.json 深入
关键字段
{
"name": "my-app",
"version": "1.0.0",
"description": "我的应用",
"main": "src/index.js",
"type": "module",
"scripts": {
"start": "node src/index.js",
"dev": "node --watch src/index.js",
"test": "node --test",
"lint": "eslint src/",
"build": "tsc"
},
"keywords": ["node", "tutorial"],
"author": "Your Name <[email protected]>",
"license": "MIT",
"engines": {
"node": ">=20.0.0"
},
"dependencies": {
"express": "^4.21.0"
},
"devDependencies": {
"eslint": "^9.0.0"
},
"private": true
}
语义化版本
主版本号.次版本号.修订号
↑ ↑ ↑
破坏性更新 新功能 Bug 修复
^4.21.0 → >=4.21.0 <5.0.0 (推荐)
~4.21.0 → >=4.21.0 <4.22.0
4.21.0 → 精确版本
* → 最新版本 (危险)
注意事项
⚠️
__dirname和__filename仅在 CommonJS 模块中可用:在 ESM 模块中需要使用import.meta.url替代。
⚠️ REPL 中的变量污染:REPL 中定义的变量会影响当前会话,使用
.clear重置。
⚠️
process.exit()的陷阱:直接调用process.exit()会跳过未完成的异步操作,推荐设置退出码让 Node.js 自然退出:process.exitCode = 1。
业务场景
- 快速验证代码片段:使用 REPL 快速测试正则表达式、日期计算等
- 开发环境脚本:使用 npm scripts 组织开发、构建、测试流程
- CLI 工具入口:通过
process.argv接收参数构建命令行工具 - 环境变量管理:通过
process.env读取配置,实现环境隔离
扩展阅读
上一章:第 2 章 · 安装与环境配置 下一章:第 4 章 · 变量与数据类型 — 深入理解 let/const/var 和 JavaScript 数据类型。