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");

注意:两种方式不能同时使用,否则会报错。关于exportsmodule.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):将一个字符串转换成buffer
  • Buffer.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学习笔记

Node.js之Web学习笔记

Node.js学习笔记

Node-学习笔记

node.js学习笔记之React

Node.js学习笔记