Node.js学习笔记
Posted 二木成林
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Node.js学习笔记相关的知识,希望对你有一定的参考价值。
笔记来自于视频:尚硅谷-快速入门nodejs
简介
概述
之前的javascript代码是在浏览器客户端执行的,而Node.js可以使JavaScript代码在服务器上运行。Node的用途:
- Web服务API,比如REST·实时多人游戏
- 后端的Web服务,例如跨域、服务器端的请求
- 基于Web的应用
- 多客户端的通信,如即时通信
Node.js的安装
在Windows系统上安装Node.js请参考:安装Node.js
在Linux系统上安装Node.js请参考:在Linux上安装Node.js
Node.js执行js文件
Node.js执行js文件,即"node js文件名.js"。
webstorm集成node.js
创建的时候指定node.js
或者在Setting中配置Node.js
模块化
模块化概念
为了让Node.js的文件可以相互调用,Node.js提供了一个简单的模块系统。
模块是Node.js 应用程序的基本组成部分,文件和模块是一一对应的。换言之,一个 Node.js 文件就是一个模块,这个文件可能是JavaScript 代码、JSON 或者编译过的C/C++ 扩展。
模块化的好处
- 降低耦合性
- 代码复用
引入模块
在Node.js中一个js文件就是一个模块。在Node.js中,通过require()
函数来引入外部模块,该函数可以传入一个文件的路径作为参数,会自动根据该路径引入外部模块,如果是相对路径必须是.
或..
开头,不能省略。
var mo = require("./world.js");// 返回一个对象,就是导入的模块
在Node.js中,每个js文件中的js代码都是独立运行在一个函数中的,而不是全局作用域,所以在一个模块中的变量和函数在其他模块中无法访问。注意:核心模块和第三方模块都可以直接在require()
方法中写模块名就可以引入,如果是自己定义的模块则需要根据路径进行引入。
可以从上面的代码中看出即使引入了其他模块,也无法调用其他模块中的属性和方法。因此需要通过exports
来向外部暴露变量和函数,只需要将需要暴露的变量或函数设置为exports
的属性即可。语法如下:
exports.变量名 = 变量值;
exports.函数名 = function ([参数列表]) {
函数体
};
示例如下:
练习:
math.js
exports.add = function (a, b) {
return a + b;
};
exports.sub = function (a, b) {
return a / b;
};
test.js
// 引入math.js模块,模块名命名为math
var math = require("./math.js");
// 调用math模块中的方法
var addResult = math.add(1, 2);
console.log(addResult);
var subResult = math.sub(4, 2);
console.log(subResult);
使用模块
模块的引用:
// 引入js文件
var 模块名 = require(模块路径);
// 引用模块
模块名.变量名;
模块名.函数名([参数列表]);
我们使用require()
引入外部模块时,使用的就是模块标识,可以通过模块标识来找到指定的模块。模块分为两大类:
- 核心模块(由Node引擎提供的模块,核心模块的标识就是模块名,既可以直接通过模块名进行引入,例如:
var mo=require("fs")
。) - 文件模块(即由用户自己创建的模块,文件模块的标识就是文件的相对路径或绝对文件,相对路径必须使用
.
或..
开头。)
实际上模块中的代码都是包装在一个函数中执行的,并且在函数执行时,同时传递进了5个实参,所以在模块中可以直接使用这五个实参。
function (exports, require, module, __filename, __dirname) {
}
在Node中有一个全局对象global
,它的作用和网页中的window
类似,在全局中创建的变量都会作为global
的属性保存,在全局中创建的函数都会作为global
的方法保存。其实Node在执行模块中的代码时首先会在代码的最顶部添加function (exports, require, module, __filename, __dirname) {
,然后在代码的最底部添加}
。所以模块中的代码是无法被外界访问到的,我们可以通过arguments.callee
来查看当前执行的函数对象,证明了模块中的代码实际上是包装在一个函数中的,所以模块中的变量也是局部变量。
其实上面的五个参数也是每个模块中的内置对象,可以直接调用,关于它们的说明如下:
exports
:该对象用来将变量或函数暴露到外部。require
:是函数,用来引入外部的模块。module
:对象,module
代表的是当前模块本身,而exports
就是module
的属性,所以既可以使用exports
导出,又可以使用module.exports
导出,更推荐后者。__filename
:属性,表示当前模块的完整路径,如C:\\Users\\abc\\projects\\test01.js
__dirname
:属性,表示当前模块所在文件夹的完整路径,如C:\\Users\\abc\\projects
module.exports
可以有两种暴露方式,语法如下:
// 第一种暴露方式
module.exports.变量名 = 变量值;
module.exports.函数名 = function ([参数列表]) {
函数体
}
// 第二种暴露方式,可以直接暴露多个变量和函数,而exports={}则不行
module.exports = {
变量名: 变量值,
函数名: function ([参数列表]) {
函数体
};
例如:
world.js
// 第一种暴露方式
// module.exports.msg = "hello world";
// module.exports.hello = function (msg) {
// console.log(msg);
// };
// 第二种暴露方式
module.exports = {
name: '张三',
age: 18,
print: function (msg) {
console.log("打印:" + msg);
}
};
hello.js
var mo = require('./world.js');
// console.log(mo.msg);
// mo.hello("你好");
console.log(mo.name);
console.log(mo.age);
mo.print("hello node.js");
注意:两种方式不能同时使用,否则会报错。关于exports
和module.exports
的区别参考:module.exports与exports,export与export default之间的关系和区别
包
概述
总结:包是模块的集合。
但包不仅仅是js模块文件,而是包含着其他文件,遵循着一定的规范。规范要求包由包结构和包描述文件两个部分组成:
- 包结构:用于组织包中的各种文件
- 包描述文件:即package.json文件,描述了包的相关信息如包名、版本、依赖等,以供外部读取分析。
包结构
包实际上是一个压缩文件,解压后还原为目录。符合包规范的目录,应该包含如下文件和文件夹:
- package.json:包的描述文件,描述了包的相关信息如包名、版本、依赖等,是必须要有的文件。
- bin:文件夹,包含了可执行的二进制文件,非必须。
- lib:文件夹,包含了js代码,非必须。
- doc:文件夹,包含了文档文件,非必须。
- test:文件夹,包含了单元测试文件,非必须。
包描述文件
包描述文件package.json就是用来描述包相关信息的一个json文件,位于包的根目录向下,是包必不可少的组成部分。但注意json文件中不可写注释。而package.json文件中的重要字段说明如下:
- name:必须要有的属性,模块名称。注意不能包含大写字母。
- version:必须要有的属性,与name属性组成了一个npm模块的唯一标识符。
- description:包描述信息,告诉别人这个包有什么作用,能提供什么功能。
- keywords:一个字符串数组,便于别人搜索到该包。
- license:规定的协议,例如MIT。
- author:该包的作者名。
- contributors:该包的一些其他贡献者姓名。
- main:指定了程序的主入口文件。
更多详细信息可以参考:npm package.json属性详解
npm
概述
总结:npm就是管理包的,类比Java中的maven。
NPM是Node Package Manager的缩写,即Node包的管理工具。对于Node而言,NPM帮助其完成了第三方模块的发布(可以将自己写的包发布到npm上)、安装(也可以通过npm来安装第三方包)和依赖(有些包会依赖其他包,而通过npm会自动下载相关的依赖包,而不需要手动去一个个寻找依赖包)等。借助NPM,Node与第三方模块之间形成了很好的一个生态系统。
在安装成功Node.js之后,npm就一起安装了,所以可以直接使用,打开DOS窗口,输入npm
出现如下帮助内容就表示npm工具是可用的。
npm可以通过一些简单的命令来安装、卸载、管理包,在命令行窗口使用。常用的命令如下:
npm -v
:查看npm工具的版本。npm version
:查看所有包的版本。npm search 包名
:根据包名搜索包,例如:npm search math
。npm install 包名
:安装指定包,注意在哪个目录执行安装命令就安装在哪个目录下,而且可以通过npm i 包名
简化安装命令来安装。执行安装命令后会生成一个node_modules文件夹和package-lock.json文件,而在node_modules文件夹下才是安装的模块。如npm install math
。npm remove 包名
:删除指定包。在任何目录下执行删除命令都可以删除,而不必要到该包的安装目录下执行。还可以通过npm r 包名
简化删除命令。如npm remove math
。npm install 包名 --save
:在安装包的时候一起添加到package.json文件中的dependencies属性中,表示依赖的包。npm install
:下载当前项目所依赖的包。如当我们从网络上下载一个项目,而该项目所需要的依赖是放在node_modules目录下的,但该目录并不会被上传,因为文件很大很多,会导致上传下载速度变慢,所以关于项目所依赖的包信息是放在package.json文件中的dependencies属性中,而执行npm install
命令就可以把这些包统一下载下来。所以以后在下载一个项目后,先执行该命令下载依赖的包。npm install 包名 -g
:全局安装包,一般用于一些工具,很多项目都会用到,而不是只有一个项目用到。npm init
:使用命令行快速创建package.json文件。而npm init -y
可以直接默认创建所有选项。npm list
:显示该项目下的包列表。
webstorm使用npm
可以在Terminal
面板执行npm命令安装、删除、管理包:
还可以在Settings
——>Languages & Frameworks
——>Node.js and NPM
中管理包,但是全局安装的。
当我们想把自己的项目上传到npm时不需要把依赖(即node_modules文件夹)也上传,上传下载速度会变慢,也不能保证是最新的,有了dependencies后就可以根据这配置信息自动下载依赖包。所以在网上下载第三方包后,先执行npm install
命令下载当前项目所依赖的包。
配置镜像
npm的服务器在国外,下载很慢,所以可以考虑使用国内有镜像服务器。有两种方式:
- 第一种方式:使用命令配置。
# 第一步,设置国内镜像网站
npm config set registry https://registry.npm.taobao.org
# 第二步,验证是否设置国内镜像成功,打印结果是上面的网站则表示配置镜像成功
npm config get registry
- 第二种方式:使用cnpm安装
# 第一步,安装cnpm
npm install -g cnpm --registry=https://registry.npm.taobao.org
# 第二步,使用cnpm进行安装等操作
cnpm install 包名
注意:通过npm下载的包都放在node_modules文件夹中,我们通过npm下载的包,可以直接通过包名引入,如var 名字 = require(包名)
。Node.js在使用模块名引入模块时,首先会在当前目录的node_modules中寻找是否含有该模块,如果有则直接使用,如果没有则去上一级目录的node_modules中寻找,如果有则直接使用,如果没有则再去上一级目录中寻找,直到找到为止,直到找到磁盘的根目录,如果依然没有则报错。
文件系统fs
Buffer
Buffer的引入:由于数组中不能存储二进制的文件,所以需要使用Buffer来专门存储二进制数据。
使用Buffer不需要引入模块,直接使用即可。在Buffer中存储的都是二进制数据,但是打印显示时都是以16进制的形式显示。
- 将字符串写入到Buffer
// 准备一个待放入到Buffer的字符串
var str = "hello world";
// 调用Buffer.from()将字符串放入到buffer中
var buf = Buffer.from(str);
console.log(buf);// <Buffer 68 65 6c 6c 6f 20 77 6f 72 6c 64>
- 创建指定大小的Buffer
// 使用Buffer.alloc(size)创建一个指定大小的buffer,size表示字节数
var buffer = Buffer.alloc(10);
// 然后可以使用类似于数组下标的方式赋值
buffer[0] = 1;
buffer[1] = 200;
buffer[2] = 123;
buffer[11] = 55;// 即使超过索引范围,也不会报错,但也不会赋值成功
console.log(buffer);
// 同样可以下标索引的方式访问buffer中的元素
console.log(buffer[1]);
// 也可以通过for循环的方式遍历
for (var i=0; i < buffer.length; i++) {
console.log(buffer[i]);
}
注意:buffer中的一个元素,占用内存的一个字节。Buffer的大小一旦确定,则不能修改,Buffer实际上是对底层内存的直接操作。
- 将buffer中的数据转换成字符串
var str = "我是一段文本数据:hello world.";
var buffer = Buffer.from(str);
// 通过buffer.toString()方法可以直接访问缓冲区的内容
console.log(buffer.toString());
Buffer相关方法:
Buffer.from(str)
:将一个字符串转换成bufferBuffer.alloc(size)
:创建一个指定大小的buffer,size指的是字节数Buffer.alloUnsafe(size)
:创建一个指定大小的buffer,但可能包含敏感数据buffer.toString()
:将buffer中的数据转换为字符串,其中buffer是创建好的缓冲区对象
模块fs概述
fs是Node提供的一个模块,该模块提供了一些API用来操作本地的文件,如打开、读取、写入文件等操作。类似于Java操作本地文件。fs是核心模块,要使用则需要对其进行加载:
var fs = require("fs");
fs模块中所有操作都有两种形式可选择:同步和异步。同步指操作代码会逐步执行,比如说读文件,要将文件所有内容都读取到内存中才会执行下面的代码。异步不会阻塞程序的执行,是在操作完成时通过回调函数将结果返回,比如说读文件,会继续执行下面的代码,而文件的所有内容会通过回调函数返回,不会影响到下面代码的执行。
文件的写入
同步文件写入
sync表示同步。
步骤如下:
第零步,导入fs模块
var fs = require("fs");
第一步,打开文件
var fd = fs.openSync(path, flags[, mode]);
参数:
- path:待打开文件的路径,如:C:\\\\Users\\\\Administrator\\\\hello.txxt
- flags:打开文件要做的操作的类型。r表示只读;w表示只写。
- mode:可选参数,设置文件的操作权限,一般不传。
返回值:
- 该方法会返回一个文件描述符作为结果,我们可以通过该描述对文件进行各种操作
第二步,向文件中写入内容
fs.writeSync(fd, string[, position[, encoding]]);
参数:
- fd:文件的描述符,通常传入openSync()方法的返回值
- string:待写入的内容
- position:可选参数,表示在文件中写入的起始位置
- encoding:可选参数,写入编码,默认为utf-8
第三步,保存并关闭文件对象
fs.closeSync(fd)
参数:
- fd:待关闭文件的描述符
例如:
// 导入fs模块
var fs = require("fs");
// 第一步,打开文件,如果文件不存在则会创建
var fd = fs.openSync("hello.txt", "w");
// 第二步,向文件中写入内容
fs.writeSync(fd, "hello world. 这是向文件中写入的内容。");
// 第三步,关闭文件
fs.closeSync(fd);
异步文件写入
步骤如下:
第零步,导入fs模块
var fs = require("fs");
第一步,打开文件,异步调用的方法结果是通过回调函数的参数返回的
fs.open(path, flags[, mode], callback)
参数:
- path:待打开文件的路径,如:C:\\\\Users\\\\Administrator\\\\hello.txxt
- flags:打开文件要做的操作的类型。r表示只读;w表示只写。
- mode:可选参数,设置文件的操作权限,一般不传。
- callback:回调函数,该回调函数有两个参数:
- err:错误对象,如果没有错误则为null
- fd:文件的描述符
第二步,向文件中写入内容
fs.write(fd, string[, position[, encoding]], callback)
参数:
- fd:文件的描述符,通常传入open()方法的返回的文件描述符对象
- string:待写入的内容
- position:可选参数,表示在文件中写入的起始位置
- encoding:可选参数,写入编码,默认为utf-8
- callback:回调函数,该回调函数有一个参数:
- err:错误对象,如果没有错误则为null
第三步,保存并关闭文件对象
fs.close(fd, callback)
参数:
- fd:文件的描述符
- callback:回调函数,该回调函数有一个参数:
- err:错误对象,如果没有错误则为null
例如:
// 第零步,导入fs模块
var fs = require("fs");
// 第一步,打开文件,异步调用的方法结果是通过回调函数的参数返回的
fs.open("hello.txt", "w", function (err, fd) {
// 不能用"err!=null"来进行判断
if (!err) {
// 第二步,向文件中写入内容
fs.write(fd, "这是同步方式向文件写入的内容。", function (err) {
if (!err) {
console.log("写入成功!")
}
// 第三步,保存并关闭文件对象
fs.close(fd, function (err) {
if (!err) {
console.log("关闭成功!")
} else {
console.log("关闭失败,error: " + err)
}
})
});
} else {
console.log(err);
}
});
简单文件写入
步骤如下:
第零步,导入fs模块
var fs = require("fs");
第一步,调用writeFile或writeFileSync方法向文件中写入内容
writeFileSync(file, data[, options]):同步写入
参数:
- file:要写入文件的路径
- data:待写入的数据
- options:可选项,是一个对象,可以对写入操作进行一些设置
writeFile(file, data[, options], callback):异步写入
参数:
- file:要写入文件的路径
- data:待写入的数据
- options:可选项,是一个对象,可以对写入操作进行一些设置
- callback:当写入完成后执行的回调函数。有一个参数err:
- err:错误对象,如果没有错误则为null
例如:
// 第零步,引入fs模块
var fs = require("fs");
// 第一步,简单文件写入
fs.writeFile("hello.txt", "这是通过简单文件方式写入的数据内容。", function (err) {
if (!err) {
console.log("写入成功!");
} else {
console.log("写入失败!");
}
});
// 或者通过writeFileSync方法写入,并添加options参数
fs.writeFileSync("hello.txt", "这是通过简单文件方式写入的数据内容。", {flag: "a"});
打开状态可以选用的值:
流式文件写入
步骤如下:
第零步,导入fs模块
var fs = require("fs");
第一步,调用createWriteStream方法创建一个可写流
var ws = fs.createWriteStream(path[, options]);
- 参数:
- path:文件路径
- options:可选参数,待配置的参数
- 返回值:
- 返回一个可写流对象
第二步,调用可写流对象的write方法向文件中输出内容
ws.write(data);
- 参数:
- data:待向文件写入的内容
第三步,关闭流对象使用end()方法而非close()方法
ws.end();
其他方法:监听流的open和close事件来监听流的打开和关闭
ws.on(事件字符串, 回调函数):可以为对象绑定一个事件。
ws.once(事件字符串, 回调函数):可以为对象绑定一个一次性的事件,该事件将会在触发一次后自动失效
例如:
// 第零步,引入fs模块
var fs = require("fs");
// 第一步,创建一个可写流
var ws = fs.createWriteStream("hello.txt");
// 第二步,向文件中写入内容
ws.write("第一行内容。\\n");
ws.write("第二行内容。\\n");
ws.write("第三行内容。\\n");
ws.write("第四行内容。\\n");
// 第三步,关闭流对象
ws.end();
// 监听流的打开
ws.once("open", function () {
console.log("流打开了...");
});
// 监听流的关闭
ws.once("close", function () {
console.log("流关闭了...");
});
文件的读取
同步文件读取
步骤如下:
第零步,导入fs模块
var fs = require("fs");
第一步,打开文件
var fd = fs.openSync(path, flags[, mode]);
参数:
- path:待打开文件的路径,如:C:\\\\Users\\\\Administrator\\\\hello.txxt
- flags:打开文件要做的操作的类型。r表示只读;w表示只写。
- mode:可选参数,设置文件的操作权限,一般不传。
返回值:
- 该方法会返回一个文件描述符作为结果,我们可以通过该描述对文件进行各种操作
第二步,向文件中写入内容
fs.readSync(fd, buffer, offset, length, position);
参数:
- fd:文件的描述符,通常传入openSync()方法的返回值
- buffer:数据将写入的缓冲区
- offset:要写入数据的 buffer 中的位置
- length:读取的字节数
- position:指定从文件中开始读取的位置
返回值:
- 返回阅读的字节数
第三步,保存并关闭文件对象
fs.closeSync(fd)
参数:
- fd:待关闭文件的描述符
例如:
// 第零步,导入fs模块
var fs = require("fs");
// 第一步,打开文件
var fd Node.js学习笔记