定义
Node.js
是一个基于 V8 JavaScript
引擎构建的运行时环境,允许你在服务器端运行 JavaScript
代码。Node.js
允许开发者使用 JavaScript
编写服务器端代码,实现前后端代码的统一,大大简化了全栈开发的流程,现在已经成为全栈开发中非常流行的一部分
也就是说Node.js
基于V8
引擎来执⾏JavaScript
的代码,但是不仅仅只有V8
引擎:
-
我们知道
V8
可以嵌⼊到任何C++
应⽤程序中,无论是Chrome
还是Node.js
,事实上都是嵌⼊了V8
引擎来执⾏JavaScript
代码 -
但是在
Chrome
浏览器中,还需要解析、渲染HTML
、CSS
等相关渲染引擎,另外还需要提供⽀持浏览器操作的API
、浏览器⾃ ⼰的事件循环等 -
在
Node.js
中我们也需要进行⼀些额外的操作,⽐如⽂件系统读/写、⽹络IO、加密、压缩解压⽂件等操作
架构
我们看下浏览器架构和Node
架构的区别:
我们编写的JavaScript
代码会经过V8
引擎,再通过Node.js
的Bindings
,将任务放到Libuv
的事件循环中,
libuv
(Unicorn Velociraptor
—独角伶盗龙)是使用C
语言编写的库,提供了事件循环、文件系统读写、网络IO、线程池等等内容
应用场景
-
应用一:目前前端开发的库都是以
node
包的形式进行管理 -
应用二:
npm、yarn、pnpm
工具成为前端开发使用最多的工具 -
应用三:越来越多的公司使用
Node.js
作为web
服务器开发、中间件、代理服务器 -
应用四:大量项目需要借助
Node.js
完成前后端渲染的同构应用 -
应用五:资深前端工程师需要为项目编写脚本工具(前端工程师编写脚本通常会使用
JavaScript
,而不是Python
或者shell
) -
应用六:很多企业在使用
Electron
来开发桌面应用程序
安装
Node.js
是在2009
年诞生的,目前最新的版本是分别是LTS v20.17.0
以及Current v22.9.0
LTS
版本:(Long-term support
, 长期支持)相对稳定一些,推荐线上环境使用该版本Current
版本:最新的Node
版本,包含很多新特性,平常学习使用可以选择current
版本
Node
的安装方式有很多:
- 可以借助于一些操作系统上的软件管理工具,比如
Mac
上的homebrew,Linux
上的yum、dnf
等 - 可以官网直接下载对应的安装包
-
window
选择.msi
安装包,Mac
选择.pkg
安装包,Linux
会在后续部署中讲解 -
安装过程中会配置环境变量(让我们可以在命令行使用)
-
并且会安装
npm(Node Package Manager)
工具
-
版本工具
如果你希望可以快速更新或切换node
多个版本时,可以借助于一些工具:下面两个工具都不支持window
nvm:Node Version Manager
n:Interactively Manage Your Node.js Versions
(交互式管理你的Node.js
版本)
针对nvm
,在GitHub
上有提供对应的window
版本:https://github.com/coreybutler/nvm-windows
-
nvm install latest
安装最新的node版本 -
nvm list
展示目前安装的所有版本 -
nvm use
切换版本
n的使用:使用时前面添加的sudo
是因为权限问题
-
npm i -g n
:直接使用npm安装即可 -
n --version
:安装成功会显示版本 -
n lts
:安装最新node
的lts
版本 -
n latest
:安装node
最新版本 -
n
:查看你安装的所有版本 -
n i version
:version
替换成你要安装的node
版本,就会安装这个版本 -
n use version
:version
替换成你要使用的node
版本,就会使用这个版本
代码执行
我们编写一个js文件,里面存放JavaScript
代码,目前我们知道有两种方式可以执行
- 将代码交给浏览器执行:
-
需要通过让浏览器加载、解析
html
代码,所以我们需要创建一个html
文件 -
在
html
中通过script
标签,引入js
文件 -
当浏览器遇到
script
标签时,就会根据src
加载、执行JavaScript
代码
-
- 将代码载入到
node
环境中执行:进入到文件所在目录,使用命令行node 文件名
就可以执行,tab
键可以补全文件名-
首先电脑上需要安装
Node.js
环境,安装过程中会自动配置环境变量 -
可以通过终端命令
node js文件名
的方式来载入和执行对应的js
文件
-
REPL
REPL
是Read-Eval-Print Loop
的简称,翻译为“读取-求值-输出”循环,是一个简单的、交互式的编程环境
- 事实上,我们浏览器的
console
就可以看成一个REPL
Node
也给我们提供了一个REPL
环境,我们可以在其中演练简单的代码
传递参数
正常情况下执行一个node程序,直接跟上我们对应的文件即可:node node.js
但在某些情况下执行node
程序的过程中,我们可能希望给node
传递一些参数:node node.js env=development 30 40
- 获取参数其实是在
process
的内置对象中,它包含版本、操作系统等,而我们的参数在argv
中,它是一个数组,我们来看下面练习代码:
// node.js文件
function add(num1, num2) {
return num1 + num2;
}
console.log("add函数结果:", add(10, 20));
console.log("process.argv:", process.argv);
argv
打印结果如下:
为什么叫argv
呢?
argc
:argument counter
的缩写,传递参数的个数argv
:argument vector
(向量、矢量)的缩写,传入的具体参数vector
翻译过来是矢量的意思,在程序中表示的是一种数据结构- 在
C++、Java
中都有这种数据结构,是一种数组结构 - 在
JavaScript
中也是一个数组,里面存储一些参数信息
输出
-
console.log
:最常用的输入内容的方式 -
console.clear
:清空控制台 -
console.trace
:打印函数的调用栈 -
还有一些其他的
console
方法:https://nodejs.org/dist/latest-v16.x/docs/api/console.html
内置模块path
我们知道在MacOS、Linux、window
上的使用路径是不一样的
window
上可以使用\
、\\
、/
来作为文件路径的分隔符- 在
MacOS、Linux、Unix
操作系统上使用/
来作为文件路径的分隔符
为了屏蔽他们之间的差异,在开发中对于路径的操作,可以使用 Node.js
中的一个内置模块path
,用于处理和操作文件和目录的路径。 它提供了一系列方法来创建、解析和格式化路径,以确保跨平台的一致性。
以下是一些常用的方法:
-
path.join([...paths])
: 连接多个路径片段,返回一个标准化的路径 -
path.resolve([...paths])
: 将路径或路径片段解析为绝对路径-
接受任意数量的路径片段作为参数,可以是绝对路径或相对路径
-
从右到左遍历提供的路径片段,一旦遇到绝对路径,所有之前的片段将被忽略,解析将从该绝对路径开始
-
如果没有遇到绝对路径,解析会使用当前工作目录(
process.cwd()
)作为起点,相对路径片段会与当前工作目录结合 -
移除多余的斜杠(
/
)和上级目录符号(..
),以生成一个规范化的路径。例如,/foo/bar/../baz
将被解析为/foo/baz
-
-
path.basename(path)
: 返回路径的最后一部分(文件名) -
path.dirname(path)
: 获取文件的父文件夹,返回路径的目录部分 -
path.extname(path)
: 返回路径的文件扩展名 -
path.parse(path)
: 返回一个对象,包含路径的各个部分(如root、dir、base、ext、name
) -
path.format(pathObject)
: 将路径对象转换为路径字符串
const path = require("path");
console.log("join:", path.join("webpack", "style", "index.js"));
console.log("resolve0:", path.resolve()); // 不传参数
console.log("resolve1:", path.resolve("study", "main.js")); // 基于当前工作目录
console.log("resolve2:", path.resolve("study", "../main.js")); // 使用相对路径
console.log("resolve3:", path.resolve("/study", "src", "main.js")); // 多个路径片段
console.log("resolve4:", path.resolve("/study", "src", "")); // 使用空路径
console.log("resolve5:", path.resolve("/study", "/src")); // 遇到/src绝对路径,忽略前面的参数
console.log("basename:", path.basename("/Node学习/study/src/main.js"));
console.log("dirname:", path.dirname("/Node学习/study/src/main.js"));
console.log("extname:", path.extname("/Node学习/study/src/main.js"));
console.log("parse:", path.parse("/Node学习/study/src/main.js"));
console.log(
"format:",
path.format({
root: "/",
dir: "/Node学习/study/src",
base: "main.js",
ext: ".js",
name: "main",
})
);
全局对象
Node
中给我们提供了⼀些全局对象,⽅便我们进行⼀些操作:某些全局对象并不常⽤,某些我们深入学习node
的时候再去理解
-
特殊的全局对象:这些全局对象实际上是模块中的变量,只是每个模块都有,看来像是全局变量,包括:
__dirname、__filename、exports、module、require()
-
__dirname
:绝对路径,获取当前⽂件所在的路径,不包括后⾯的⽂件名 -
__filename
:绝对路径,获取当前⽂件所在的路径和⽂件名称,包括后⾯的⽂件名称 -
后面三个在模块化中讲解具体学习这篇文章:待后面补充
-
-
常见的全局对象:
-
process
对象:process
提供了Node
进程中相关的信息⽐如
Node
的运⾏环境、参数信息等;
后⾯在项⽬中,会学习如何将⼀些环境变量读取到process
的env
中
-
console
对象:提供了简单的调试控制台 -
定时器函数:在
Node
中使⽤定时器有好⼏种⽅式setTimeout(callback, delay, args)
:callback
在delay
毫秒后执⾏⼀次setInterval(callback, delay, args)
:callback每delay毫秒重复执⾏⼀次setImmediate(callback, args)
:callback I/O事件后的回调的“⽴即”执⾏,后面事件循环中具体讲解process.nextTick(callback, args)
:添加到下⼀次tick队列中,后面事件循环中具体讲解 -
global
对象:事实上前面的process、console、setTimeout
等都有被放到global
中在新的标准中还有⼀个
globalThis
,因为在浏览器中全局对象是window
,在node中全局对象是global
,所以在新的标准中就统一了一个globalThis
在浏览器中执⾏的
JavaScript
代码,如果我们在顶级范围内通过var
定义的⼀个属性,默认会被添加到window
对象上但是在
node
中,我们通过var
定义⼀个变量,它只是在当前模块中有⼀个变量,不会放到全局中
-