JavaScript 笔记(十二):Node
Node.js 核心基础
Node.js 简介
Node.js 是一款基于 Chrome V8 引擎 的 JavaScript 运行环境,V8 引擎是一个专门用于解释和执行 JavaScript 代码的虚拟机,程序如果集成了 V8 引擎,便可以执行 JavaScript 代码
Node.js 不是编程语言,是一个运行环境,由于此运行环境集成了 V8 引擎,所以可以在此环境下运行 JavaScript 代码
搭建 Node.js 运行环境
- http://nodejs.cn/
- msi
- zip -> 环境变量
- NVM
在命令行中执行命令
node -v查看版本号
在 Node.js 中执行 JS
- 命令行
- 在命令行中执行命令
node打开 REPL(Read Eval Print Loop) 环境
- 在命令行中执行命令
- .js 文件
- 在命令行中执行命令
node [.jspath]
- 在命令行中执行命令
浏览器与 Node.js 的区别
- 内置对象
- 浏览器环境提供了 window 全局对象
- Node.js 环境提供的全局对象不是 window,而是 global
- this 默认值
- 浏览器环境中全局 this 默认指向 window
- Node.js 环境中全局 this 默认指向空对象
{}
- API
- 浏览器环境提供了 DOM 和 BOM 相关的 API
- Node.js 环境中没有 DOM 和 BOM 的概念,也没有相关的 API
Node.js 的全局变量和方法
在 Node.js 提供了一些全局变量和方法,示例如下:
console.log(__dirname); // E:\LearnNotes\nodejs\code
console.log(__filename); // E:\LearnNotes\nodejs\code\global.js
console.log("Reyn Morales"); // Reyn Morales
setTimeout(() => {
console.log("Hello World"); // Hello World
}, 5000);
在上述示例中,可以在 Node.js 中使用 console / setTimeout 全局方法,console 和 setTimeout 方法与浏览器环境中的方法相同,可以使用 __dirname / __filename 全局变量,__dirname 表示执行文件所在的绝对路径,__filename 以绝对路径的形式表示执行文件的名称
Node.js 模块
在学习框架时,我们可以发现绝大多数框架的源码总是以一个立即执行的函数作为核心代码的最外层结构,此形式即为以浏览器为宿主下的模块开发,以一个类或者一个立即执行的函数作为一个模块,示例如下:
;(function(window){
let name = "Reyn Morales";
// ...
let say = () => console.log("Hello World");
// ...
/* 属性 */
window.name = name;
// ...
/* 方法 */
window.say = say;
// ...
})(window);
由于以浏览器为宿主下的模块开发没有相应的标准和规范,所以存在某些问题,而在 Node.js 中采用了 CommonJS 规范实现了模块系统
CommonJS 规范规定了如何定义一个模块、如何导出模块中的内容、以及如何使用定义好的模块,内容如下:
- 模块以文件为单位,有多少个文件就有多少个模块
- 每个文件中的内容均是私有的,其它文件不可访问
- 每个文件中的内容必须通过 exports 实例导出之后,其它文件才可以使用
- 每个文件必须调用 require 函数导入模块,才能使用相应模块导出的内容
exports 示例如下:
/**
* FILE NAME: exports.js
*/
let name = "Reyn Morales";
let say = () => console.log("Hello World");
exports.str = name;
exports.say = say;
require 示例如下:
/**
* FILE NAME: require.js
*/
let exmp = require("./exports");
console.log(exmp.str); // Reyn Morales
exmp.say(); // Hello World
Node.js 中除了可以使用 exports 实例导出模块内容之外,也可以使用 module.exports 实例导出模块,示例如下:
/**
* FILE NAME: exports.js
*/
let name = "Reyn Morales";
let say = () => console.log("Hello World");
module.exports.str = name;
module.exports.say = say;
module.exports 和 exports 的区别在于前者在导出时可以不同指定属性或方法名称,示例如下:
/**
* FILE NAME: exports.js
*/
let name = "Reyn Morales";
module.exports = name;
此时如果访问 require 导入的实例:
/**
* FILE NAME: require.js
*/
let exmp = require("./exports");
console.log(exmp); // Reyn Morales
此外,类似于浏览器的惯用做法,Node.js 可以将变量和函数绑定到 global 全局对象中,示例如下:
/**
* FILE NAME: exports.js
*/
let name = "Reyn Morales";
let say = () => console.log("Hello World");
global.str = name;
global.say = say;
此时必须调用 require 函数才可以访问,示例如下:
/**
* FILE NAME: require.js
*/
let exmp = require("./exports");
console.log(str);
say();
由于使用 global 违反了 CommonJS 规范,所以不建议使用
另外,通过 require 函数导入模块时,可以不说明模块类型(后缀名),此时系统将依次查找以 .js、.json 以及 .node 为后缀的相应文件,不论是哪一种,导入后都将结果转换为一个实例返回,示例如下:
- JSON
{
"name": "Reyn Morales",
"age": 22
}
- JavaScript
/**
* FILE NAME: print.js
*/
let person = require("./person");
console.log(person); // { name: 'Reyn Morales', age: 22 }
此外,通过 require 不仅可以导入自定义模块(文件模块),还可以导入系统模块(核心模块)和第三方模块,在导入自定义模块时,必须加上路径,否则报错,如果导入系统模块,那么程序将在环境变量配置的路径中查找;如果导入第三方模块,那么程序将在 module.paths 数组所保存的路径中依次查找
Node.js 包管理工具
在模块开发过程中,为了便于维护、减少出错,通常在一个模块中只完成一个特定的功能,而在某些情况下,某个功能必须由多个模块组成,为了提高项目的可维护性,此时可以通过某种工具来管理、说明以及维护所有模块之间的关系,通常将所有被管理的模块称为包,包可以由一个或若干个模块构成,所以此工具即被称为包管理工具
npm
Node.js 为了方便开发者发布、安装和管理包,推出了 npm(Node Package Manager)包管理工具
npm 在配置 Node.js 环境时,由系统自动安装,所以可以立即使用
全局
通过 npm 可以将包存储到全局 node_modules 中,在计算机的任何位置都可以使用 node_modules 中的模块,命令如下:
| 命令 | 说明 |
|---|---|
| npm install -g {package} | 将 package 以全局模式安装,默认为最新版本 |
| npm install -g {package}@{version} | 将指定 version 的 package 以全局模式安装 |
| npm uninstall -g {package} | 将 package 以全局模式卸载 |
| npm update -g {package} | 将 package 以全局模式更新到最新版本 |
通过命令
npm config ls -l可以查看 npm 的配置信息,prefix 所描述的路径即为包以全局模式安装的路径前缀
示例如下:
- 安装(默认版本)
npm install -g nrm
- 卸载
npm uninstall -g nrm
- 安装(特定版本)
npm install -g nrm@1.0.0
如果在
/E目录下启动 cmd,并执行命令nrm --version,结果为1.0.0
- 更新(最新版本)
npm update -g nrm
此时如果在任意路径下启动 cmd,并执行
nrm --version,结果为1.2.5,在 nmp 官方 查询 nrm 包的最新版本为1.2.5
默认情况下,npm 从国外服务器下载资源,速度较慢,nrm 可以切换资源下载地址,从而提高下载速度,首先,通过命令 nrm ls 查看允许切换的资源地址,之后通过命令 nrm use taobao 将资源下载地址切换到淘宝,结果如下:
Registry has been set to: https://registry.npmmirror.com/
此时即将资源地址切换为国内,另外,通过 cnpm 包管理工具安装模块时,也可以自动将资源地址切换为国内,通常情况下,将 cnpm 以全局模式安装,之后就可以使用 cnpm 安装包,使用方式和 npm 基本相同,区别在于将 npm 切换为 cnpm,示例如下:
cnpm install electron --save-dev
本地
通过 npm 也可以将包存储到本地项目的 node_modules 中,此时 node_modules 中的模块只能在本地项目中引用,在将包安装到本地之前,必须在本地项目目录下通过 npm init 或者 npm init -y 命令初始化 package.json 文件,内容如下:
{
"name": "npm",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
此文件中描述了项目的名称、版本、作者、许可证和所需的模块等基本信息,通过
npm install命令安装包时,此命令根据package.json配置文件自动下载所需的模块,即配置项目的运行和开发环境
npm 的本地项目包管理命令如下所示:
| 命令 | 说明 |
|---|---|
| npm install {package} | 将 package 以本地模式安装到当前项目中,默认作为生产环境包的依赖 |
| npm uninstall {package} | 将 package 以本地模式从当前项目中卸载 |
| npm upgrade {package} | 将 package 以本地模式更新到最新版本 |
| npm install {package} --save | 将 package 作为当前项目的生产环境包的依赖安装到本地项目中 |
| npm install {package} --save-dev | 将 package 作为当前项目的开发环境包的依赖安装到本地项目中 |
生产环境包是指在本地项目中引用的用于实际实现某个功能的包,开发环境包是指在本地项目中引用的用于调式功能等辅助开发的工具包,此类包被卸载之后并不影响本地项目的使用
示例如下:
- 安装(默认)
npm install jquery
- 安装(生产环境包)
npm install swiper --save
- 安装(开发环境包)
npm install fastclick --save-dev
此时若打开 package.json 文件,内容如下:
{
"name": "npm",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"jquery": "^3.6.1",
"swiper": "^8.4.3"
},
"devDependencies": {
"fastclick": "^1.0.6"
}
}
在
package.json文件中,dependencies 即为生产环境包,devDependencies 即为开发环境包,不论是哪一种包,保存的内容均为包名和版本号,版本号有 3 种形式,不同的形式在依赖被安装时所选择的版本不同,示例和说明如下:
| 示例 | 说明 |
|---|---|
| 3.6.1 | 3.6.1 指定版本 |
| ^3.6.1 | 3.6.X 中的最新版本 |
| ~3.6.1 | 3.X.X 中的最新版本 |
此外,若将项目分享给别人时,并不需要拷贝本地项目的 node_modules 包文件,而是拷贝配置文件即可,被分享者获取到项目的配置文件之后,通过 npm i 命令即可自动配置项目的生产和开发环境,即自动安装项目依赖的生产环境包和开发环境包,此外,通过 npm i --production 命令将自动安装项目依赖的生产环境包,通过 npm i --development 命令将自动安装项目依赖的开发环境包
yarn
yarn 是由 Facebook、Google、Exponent 和 Tilde 联合推出的 JS 包管理工具,目的在于弥补 npm 5.0 版本之前的一些缺陷,不过,现在 npm 已经更新到 8.x 版本,由于 npm 随着升级的优化性能以及超越了 yarn,所以不再详细介绍,yarn 的使用和 npm 类似,区别在于命令的选项不同,例如 npm 中安装、卸载和更新的选项分别为 install、uninstall 和 update,在 yarn 中分别是 add、remove 和 upgrade,如果以全局模式管理,npm 通过 -g 选项说明,而 yarn 中通过 global 选项说明
Node.js 核心 API
Buffer
在 Node.js 中,Buffer 类专门用于以 2 进制形式存储字节数据
由于 Buffer 相关的内容已经绑定在了 global 上,所以不用导入即可使用
基本使用
Buffer 类通过 alloc 静态方法开辟指定大小的存储空间,并且可以初始化数据和字符编码,原型如下:
Buffer.alloc(size[, fill[, encoding]])
示例如下:
let buf = Buffer.alloc(5);
console.log(buf); // <Buffer 00 00 00 00 00>
默认情况下以 0 填充数据、utf8 编码,此外,如果通过 log 打印 Buffer 实例,那么将以 16 进制的形式输出实例中的内容,示例如下:
let buf = Buffer.alloc(5, 15);
console.log(buf); // <Buffer 0f 0f 0f 0f 0f>
此外,Buffer 类可以通过 from 静态方法根据参数自动创建实例,原型如下:
Buffer.from(string[, encoding])
示例如下:
let buf = Buffer.from("reyn");
console.log(buf); // <Buffer 72 65 79 6e>
如果参数为字符串,那么将以二进制形式存储各个字符的 ASCII 码,此外,from 也可以传入一个数组,原型如下:
Buffer.from(array)
示例如下:
let buf = Buffer.from([1, 3, 5]);
console.log(buf); // <Buffer 01 03 05>
实际上,Buffer 实例的本质是一个数组,示例如下:
let buf = Buffer.from([1, 3, 5]);
console.log(buf); // <Buffer 01 03 05>
buf[0] = 7;
console.log(buf.length); // 3
console.log(buf); // <Buffer 07 03 05>
实例方法
- toString
将 Buffer 实例中存储的字节数据转换为字符串,示例如下:
let buf = Buffer.from("Reyn");
console.log(buf); // <Buffer 52 65 79 6e>
console.log(buf.toString()); // Reyn
- write
向 Buffer 实例中写入数据,原型如下:
buf.write(string[, offset[, length]][, encoding])
offset 为字节的起始下标,length 为字节个数,示例如下:
let buf = Buffer.alloc(5);
buf.write("Morales", 2, 2);
console.log(buf); // <Buffer 00 00 4d 6f 00>
console.log(byteNum); // 2
- slice
从存在的 Buffer 实例中截取一个新的 Buffer,原型如下:
buf.slice([start[, end]])
start 为截取的起始下标(默认值为 0),end 为截取的结束下标(不包含)
示例如下:
let buf = Buffer.alloc(5);
buf.write("Morales");
console.log(buf.toString()); // Moral
let subBuf = buf.slice(2, 4);
console.log(subBuf.toString()); // ra
必须注意的是,如果被写入的字节个数大于 Buffer 实例长度,那么剩余的字节将被丢弃,此外,每个中文字符占用 3 个字节,示例如下:
let buf = Buffer.from("乔布斯");
console.log(buf.length); // 9
静态方法
- isEncoding
原型如下:
Buffer.isEncoding(encoding)
示例如下:
console.log(Buffer.isEncoding("gbk")); // false
- isBuffer
原型如下:
Buffer.isBuffer(obj)
示例如下:
let arr = new Array();
console.log(Buffer.isBuffer(arr)); // false
let buf = Buffer.alloc(5);
console.log(Buffer.isBuffer(buf)); // true
- byteLength
原型如下:
Buffer.byteLength(string[, encoding])
示例如下:
let buf = Buffer.alloc(5);
console.log(Buffer.byteLength(buf)); // 5
- concat
原型如下:
Buffer.concat(list[, totalLength])
示例如下:
let buf1 = Buffer.from("0320 ");
let buf2 = Buffer.from("Reyn");
let buf3 = Buffer.from(" Moralers");
let totalBuf = Buffer.concat([buf1, buf2, buf3]);
console.log(totalBuf.toString()); // 0320 Reyn Moralers
concat 静态方法不可以合并以数组构造 Buffer 实例
path
在 Node.js 中,path 模块专门用于处理路径相关内容,在使用前必须通过 require 方法导入,示例如下:
let path = require("path");
path 是 Node.js 的核心模块之一,所以不用以路径的形式导入
属性
- path.sep
sep 属性保存了系统的路径分隔符(windows 系统中为 \、Linux 系统中为 /)
示例如下:
console.log(path.sep);
- path.delimiter
delimiter 属性保存了系统的环境变量分隔符(windows 系统中为 ;、Linux 系统中为 :)
示例如下:
console.log(path.delimiter);
方法
- path.parse(path)
parse 方法将一个目录(字符串)解析为一个实例,示例如下:
let pathStr = "/a/b/c/index.html";
let pathObj = path.parse(pathStr);
console.log(pathObj);
输出内容如下:
{

最低0.47元/天 解锁文章
681

被折叠的 条评论
为什么被折叠?



