Node.js 第一个程序
上一篇 Node.js 是什么 说清了 Node.js 的来龙去脉,这篇开始动手写代码。你会学到运行 JS 的两种方式,认识 global、console、process 这三个 Node.js 环境的核心对象。跑通这几个例子,你就正式踏入 Node.js 世界了。
运行 JS 的两种方式
方式一,REPL 交互式环境
REPL 是 Read-Eval-Print-Loop 的缩写,输入一行立即执行一行。终端里直接敲 node 回车就进入这个环境。
node
# 进入 REPL,提示符变成 >
> 1 + 2
3
> const name = "小明"
undefined
> name
'小明'
> .exit
输入 1 + 2 立刻返回 3,变量也能记住。适合随手验证语法,退出用 .exit 或按两次 Ctrl+C。
方式二,运行 JS 文件
正式写程序都放在 .js 文件里,用 node 文件名.js 运行。
node hello.js
文件方式才是实际开发的主力,REPL 只用来临时测试。两种方式都走同一套 V8 引擎,语法完全一致。
global 对象
global 对应浏览器的 window
浏览器里 window 是全局对象,Node.js 里对应的是 global。console、setTimeout 这些内置对象都挂在它上面。
console.log(global.console === console); // true,同一个对象
console.log(global.process === process); // true,同一个对象
| 对比项 | 浏览器 window | Node.js global |
|---|---|---|
| document | 有 | 没有 |
| location | 有 | 没有 |
| process | 没有 | 有 |
| __dirname | 没有 | 有 |
globalThis 统一访问
为了写代码时不区分环境,ES2020 引入了 globalThis,无论在浏览器还是 Node.js 里都指向当前环境的全局对象。
// 在浏览器里 globalThis 就是 window,在 Node.js 里就是 global
console.log(globalThis === global); // Node.js 中输出 true
全局对象可以直接用名字访问,console.log(global) 和 console.log(globalThis) 结果相同,日常写代码加不加 global. 前缀都行。
浏览器有而 Node.js 没有的
浏览器里随手可用的 document 和 window,在 Node.js 里都不存在。用 typeof 验证最直观,它不会因为变量不存在而报错。
// typeof 不存在的变量返回 "undefined",不会抛错
console.log(typeof document); // undefined
console.log(typeof window); // undefined
如果直接写 document.title,Node.js 会报 document is not defined。原因很简单,服务器环境里没有页面这个概念,自然没有文档对象。
console 对象
console.log 输出到标准输出(stdout),运行程序时直接显示在终端。它支持 %s 和 %d 这类格式化占位符。
const name = "小明";
const age = 18;
console.log("我叫 %s,今年 %d 岁", name, age);
// 我叫 小明,今年 18 岁
console.error 输出到标准错误(stderr),终端里照样能看见,但语义上表示出错信息,日志系统会区分两者。
console.error("这里出错了");
调试时还有 console.table,把对象数组打印成表格,看数据比 console.log 清楚得多。
process 对象
process 是 Node.js 的进程对象,程序运行时代表当前这个进程,信息量很大。
process.argv 命令行参数
node greet.js 小明
// greet.js
console.log(process.argv);
// 输出。
// [ 'C:\\node\\node.exe', 'C:\\projects\\greet.js', '小明' ]
前两个位置是固定的,第一个是 node 可执行文件的路径,第二个是当前文件路径,从第三个开始才是你传的参数。取值要写 process.argv[2] 起步。
process.env 环境变量
process.env 是包含所有环境变量的对象,按操作系统不同内容也不一样。
console.log(process.env.PATH); // 系统路径
console.log(process.env.NODE_ENV); // 开发中常用来区分环境
其他常用属性
console.log(process.platform); // win32 / darwin / linux,判断操作系统
console.log(process.cwd()); // 当前工作目录,程序从哪个目录启动
process.exit(1); // 退出进程,0 表示正常,非 0 表示异常
// 后面的代码不会执行
process.cwd() 返回的是启动目录,不等于文件所在目录,新手经常在这里踩坑。
实践
hello.js
新建一个 hello.js。
// hello.js
console.log("Hello Node.js");
运行。
node hello.js
# 输出 Hello Node.js
greet.js 接收命令行参数
再写一个能打招呼的程序。
// greet.js
const args = process.argv.slice(2); // 丢掉前两个固定项,只留用户参数
if (args.length === 0) {
console.error("请提供名字,例如 node greet.js 小明");
process.exit(1); // 参数缺失,以错误码退出
}
console.log("你好,%s!欢迎学习 Node.js", args[0]);
node greet.js 小明
# 你好,小明!欢迎学习 Node.js
node greet.js
# 请提供名字,例如 node greet.js 小明
常见坑
- 在 REPL 里写的变量,退出后全部清空,想保留代码就存成文件。
process.argv的参数从第 3 个(下标 2)开始取,前两个是 node 路径和文件路径。- 直接写
document或window会报未定义,Node.js 里没有浏览器对象,用typeof检查最安全。 process.cwd()是启动目录不是文件目录,在别的目录启动程序时结果会不一样。console.error也是输出到终端的,肉眼分辨不出差别,但脚本管道和日志系统会区分 stdout 与 stderr。
运行程序的两种方式和这三个核心对象都摸清了,下一步学怎么把代码拆成多个文件,见 Node.js 模块系统。