Node.js学习第三天
1.模块化
1.1 模块化的定义
- 模块化指解决一个复杂问题时,自顶向下逐层把系统划分为若干模块的过程。对应整个系统来说,模块是可组合、分解、更换的单元
1.2 编程领域的模块化
- 遵守固定的规则,把一个大文件拆分成独立并相互依赖的多个小模块
- 好处
- 提高了代码的复用性
- 提供了代码的可维护性
- 可以实现按需加载
1.3 模块化的规范
- 对代码进行模块化的拆分和组合时,需要遵守的那些规则
- 使用什么样的语法格式来引用模块
- 在模块中使用什么样的语法格式向外暴露成员
2.Node.js中的模块化
2.1 Node.js中模块的分类
- 内置模块:Node.js官方提供,如fs,path,http
- 自定义模块:用户创建的每个.js文件
- **第三方模块:由第三方开发出来的模块,并非官方提供,**也不是用户创建的自定义模块,使用前需要下载
2.2 加载模块
- 使用require()方法,可以加载需要的内置模块,用户自定义模块,第三方模块
// 加载fs模块
const fs = require('fs')
//加载用户自定义模块
const zdy = require('./zdy.js')
// 加载第三方模块
const moment=require('moment')
示例
- zdy.js
console.log("自定义模块被加载");
- test.js
const zdy = require('./02.zdy.js')
console.log(zdy);
- 运行test.js效果图
注意点
-
使用require()方法加载其他模块时,会执行被加载模块中的代码
-
使用require()方法加载自定义模块时,可以省略.js后缀名
const zdy = require('./02.zdy')
console.log(zdy);
2.3 模块作用域
- 和函数作用域类似,在自定义模块中定义的变量、方法,只能在当前模块内被访问
- 图解
-
好处
- 防止了全局变量污染的问题
示例
- zdy.js
console.log("自定义模块被加载");
const ename = '张三';
- test.js
const zdy = require('./02.zdy.js')
console.log(zdy);
- 效果图
2.4 向外共享模块作用域中的成员
2.4.1 module对象
- 每个.js自定义模块中都有一个module对象,里面存储了和当前模块有关的信息
示例
console.log(module);
- 效果图
2.4.2 module.exports对象
- 在自定义模块中,可以使用module.exports对象,将模块内的成员共享出去,供外界使用
- 使用require()方法导入自定义模块时,得到的就是module.exports所指向的对象
示例
- 自定义模块.js
// 在module.exports对象上挂载 username属性
module.exports.username = 'zs';
// 在module.exports对象上挂载sayHello()方法
module.exports.sayHello = function() {
console.log("hello!");
}
const age = 20;
module.exports.age = age;
- 测试.js
const zdy = require('./06.自定义模块')
console.log(zdy);
- 效果图
2.4.3 共享成员时的注意点
- 使用require()方法导入模块时,导入的结果,永远以module.exports指向的对象为准
示例
- 自定义模块2
// 要共享的成员永远以module.exports指向的对象为准
module.exports.username = 'zd';
module.exports.sayHello = function() {
console.log("hello");
}
// 指向另一个对象
module.exports = {
ename: 'k',
eage: '18',
sayHi() {
console.log("Hi");
}
}
- 测试
const zdy2 = require('./08.自定义模块2')
console.log(zdy2);
- 效果图
2.4.4 exports对象
-
exports对象和module.exports指向同一个对象,最终共享的结果,以module.exports指向的对象为准
-
示例
console.log(exports);
console.log(module.exports);
console.log(exports === module.exports);
- 效果图
示例
- 自定义模块3
module.exports.age = '19'
exports.username = 'zs'
exports.age = '18'
exports.sayHello = function() {
console.log("Hello");
}
- 测试
const zdy3 = require('./11.自定义模块3')
console.log(zdy3);
- 效果图
2.4.5 exports 和module.exports的使用误区
- 得到的永远是module.exports指向的对象
- 为了防止混乱,不要同时使用exports和module.exports
2.4.6 Node.js中的模块化规范
- 遵循CommonJs模块化规范
- CommonJs规定
- 每个模块内部,module变量代表当前模块
- module变量是一个对象,他的exports属性(即module.exports)是对外的接口
- 加载某个模块,其实就是加载该模块的module.exports属性,require()方法用于加载模块
3.npm和包
3.1 包
- Node.js中的第三方模块叫做包
- 包由第三方个人或团队开发出来的
- Node.js的包免费开源
3.2 包的作用
- Node.js的内置模块仅仅提供了一些底层的API,包是基于内置模块封装出来的,提高了开发效率
- 包与内置模块的关系,类似与jQuery和浏览器内置API之间的关系
3.3 包的下载
-
搜索包的网址:<npm (npmjs.com)>
-
下载包的网址:<https://registry.npmjs.org>
3.4 moment包的使用
- 普通方法格式化日期
- 自定义日期格式化模块
function dateFormat(dt) {
var y = dt.getFullYear();
var m = padZero(dt.getMonth() + 1);
var d = padZero(dt.getDate());
var h = padZero(dt.getHours());
var mm = padZero(dt.getMinutes());
var s = padZero(dt.getSeconds());
return `${y}-${m}-${d} ${h}:${mm}:${s}`
}
// 补零函数
function padZero(n) {
return n < 10 ? '0' + n : n;
}
module.exports = {
dateFormat
}
- 测试日期格式化模块
var format = require('./14.自定义日期格式化')
var date = new Date();
var str = format.dateFormat(date);
console.log(str);
- 效果图
直接使用moment包来格式化日期
- 下载包(管理员身份运行,先进入项目所在目录,再下载)
npm install moment
- 使用文档
<Moment.js | Docs (momentjs.com)>
// 导入moment包
const mt = require("moment")
// mt()获取当前时间,format日期格式化
var dt = mt().format("YYYY-MM-DD HH:mm:ss");
console.log(dt);
- 效果图
3.4 装包后多的文件
- node_modules文件夹和package-lock.json的配置文件
- node_modules用来存放已安装到项目中的包,require()导入第三方包时,从这个目录查找并加载包
- package-lock.json:记录每一个包下的下载信息,例如包名,版本号等
3.5 包的版本号
-
格式:点分十进制,三位数字,如2.24.0
- 第一位数字:大版本:底层重新设计
- 第二位数字:功能版本:功能增添
- 第三位数字:bug修复版本:修复bug
-
版本提升规则:只要前面的版本号增长了,后面的版本号归零
3.6 包管理配置文件
- npm规定:在项目根目录中,必须提供一个叫做package.json的包管理配置文件,记录相关信息
- 项目的名称,版本号,描述
- 项目中都用到了哪些包
- 哪些包只在开发期间会用到
- 哪些包在开发和部署阶段都需要用到
-
package.json配置文件
- 创建方法
npm init -y
- 注意点
- 只能在英文的目录下成功运行,不能使用中午,不能使用空格
- 创建成功后,提高npm install 命令安装包时,npm包管理工具会自动的把包的名称和版本号,记录到package.json中
-
dependencies 节点
- package.json 配置文件中的节点
- 专门记录安装了哪些包
- 同时安装多个包,包名之间用空格隔开
npm i jquery art-template
- 一次性安装所有的依赖包(存在package.json配置文件)
// 执行npm install 或 npm i 命令时,npm包管理工具会读取package.json 中的dependencies 节点
// 读取节点中的包名称和版本号后,就会把这些包一次性全部下载
npm install
- 卸载包
- 卸载包之后,package.json的dependencies节点的相关记录也会删除
npm uninstall 包的名称
-
devDependencies节点
- 节点中的包在项目开发阶段会用到,项目上线后不会用到
-
Dependencies节点
- 节点中的包在开发和上线后都需要用到
-
将包记录到devDependencies节点中
npm i 包名 -D // 或者 npm install 包名 --save-dev
3.7 解决下包慢的问题
- 切换npm的下包镜像源
# 查看当前的下包镜像源
npm config get registry
# 将下包镜像源切换为淘宝镜像源
npm config set registry=https://registry.npmmirror.com/
# 检查镜像源是否切换成功
npm config get registry
3.8 nrm
- 一个工具,方便切换下包的镜像源,快速查看和切换下包的镜像源
# 提高 npm包管理器,安装nrm为全局可用的工具
npm i nrm -g
# 查看可用的镜像源
nrm ls
# 将下包的镜像源切换为淘宝
nrm use taobao
3.9 包的分类
-
全局包
- 在执行npm install 命令时,如果提供了-g参数,则会把包安装为全局包
npm i 包名 -g #全局安装指定的包 npm uninstall 包名 -g #x
- 注意点
- 只有工具性质的包,才有全局安装的必要性,因为他们提供了好用的终端命令
- 判读某个包是否需要全局安装才能使用,可以参考官方文档
-
项目包
-
安装到项目的node_modules目录中的包,都是项目包
-
开发依赖包:(被记录到devDependencies节点中的包,只会在开发期间用到)
-
核心依赖包:(被记录到Dependencies节点中的包,在开发期间和项目上线之后都会用到)
-
安装方法
npm i 包名 -D #开发依赖包(记录到devDepdentencies节点下) npm i 包名 # 核心依赖包(记录到Dependencies节点下)
-
3.10 i5ting_toc
- 一个把md文档转为html页面的小工具
# 将i5ting_toc 安装为全局包
npm install i5ting_toc -g
#调用i5ting_toc 实现md转html的功能
i5ting_toc -f 要转换的md文件路径 -o
3.11 规范的包结构
- 包必须以单独的目录存在
- 包的顶级目录下包含package.json这个包管理配置文件
- package.json包含name,version,main三个属性,代表包名,包版本,包的入口(js文件所在)
4.开发自己的包
- 包实现的功能
- 格式化日期
- 转义html特殊字符
- html字符还原
- 初始化包的基本结构
- 新建day03-utils文件夹,作为包的根目录
- 在day03-utils文件夹中新建三个文件
- index.js
- package.json(可使用npm init -y) 来自动创建,再修改一下
- README.md说明文档
- 包的功能的模块化
- 根目录下创建src文件夹
- 将格式化日期的功能拆分到src—>dateDateFormat.js中
- 处理html的字符串拆分到src->htmlTo
- index.js导入上述两个功能,在把功能暴露出去
- package.json
{
"name": "day03-utils",
"version": "1.0.0",
"description": "用于html的转换,时间日期格式化",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": ["lingxin", "html", "Formdate"],
"author": "lingxin",
"license": "ISC"
}
- index.js
// 这是day03-utils包的入口
// 导入dateFormat和htmlTo包
const date = require('./src/dateFormat');
const htmlTo = require('./src/htmlTo')
module.exports = {
// 使用展开运算符,将对象成员展开
...date,
...htmlTo
}
- dateFormat.js
// 定义一个格式化日期的函数
function dateFormat(dateStr) {
var date = new Date(dateStr);
var y = date.getFullYear();
var m = padZero(date.getMonth() + 1);
var d = padZero(date.getDate());
var h = padZero(date.getHours());
var mm = padZero(date.getMinutes());
var ss = padZero(date.getSeconds());
return `${y}-${m}-${d}-${h}-${mm}-${ss}`
}
// 补零函数
function padZero(n) {
return n < 10 ? '0' + n : n;
}
module.exports = {
dateFormat
}
- htmlTo.js
// 将html标签中的<> & 和 " 转换为相应的实体字符
function htmlToEntity(htmlStr) {
return htmlStr.replace(/<|>|"|&/g, function(match) {
switch (match) {
case '<':
return '<'
case '>':
return '>'
case '"':
return '"'
case '&':
return '&'
}
})
}
// 将实体字符还原回来
function htmlTochar(htmlStr) {
return htmlStr.replace(/<|>|&|"/g, function(match) {
switch (match) {
case '<':
return '<'
case '>':
return '>'
case '&':
return '&'
case '"':
return '"'
}
})
}
module.exports = {
htmlToEntity,
htmlTochar
}
- README.md
## 安装
```shell
npm install day03-utils
```
## 导入
```js
const d3 = require('day03-utils');
```
## 格式化日期函数的使用
```js
var time = d3.dateFormat(new Date());
console.log(time);
// 输出结果 2022-03-14-18-53-18
```
## 转义特殊字符的使用
```js
// 测试字符转义
var str2 = d3.htmlToEntity(str);
console.log(str2);
// 输出结果:<h1 title="666">123&nbsp;<h1/>
```
## 还原特殊字符的使用
```js
var str2 = d3.htmlToEntity(str);
// 测试字符还原
var str3 = d3.htmlTochar(str2);
console.log(str3);
// 输出结果:<h1 title="666">123 <h1/>
```
## 开源协议
ISC
5.发布包到npm上
-
注册npm的账号
-
在终端上登录npm账户
- 首先将下包的服务器切换成npm的官方服务器
- 使用nrm工具换源
- 终端登录
npm login
-
发布包到npm
- 将终端切换到根目录下
- 在npm官网中查看包名是否雷同(雷同不能发布)
- 输入发包命令
npm publish
-
删除已发布的包
npm unpublish 包名 --force
- 注意点
6. 模块加载机制
6.1 模块优先从缓存中加载
- 模块在第一次被加载时里面的代码会被执行,加载后模块被缓存,多次调用require()方法不会导致模块的代表被多次执行
示例
- 自定义模块4
console.log("hello");
- 测试自定义模块4
require('./17.自定义模块4')
require('./17.自定义模块4')
require('./17.自定义模块4')
- 效果图
6.2 内置模块的加载机制
- 内置模块是由Node.js官方提供的,内置模块的加载优先级最高
- 例如,require(‘fs’)始终返回内置的fs模块,即使在node_modules目录下有名字相同的包也叫做fs
6.3 自定义模块的加载机制
- 使用require()加载自定义模块时,必须指定以./或…/开头的路径标识符,在加载自定义模块时,如果没有指定./或…/这样的路径标识符,则node会把他当作内置模块或第三方模块进行加载