目录
模块化概念:
什么是模块化:
模块化是指解决一个复杂问题,自顶向下逐层把系统划范围若干模块的过程。对于整个系统来说,模块是可组合,可分解和可变换的单元。
模块化规范:
模块化规范就是对代码进行模块化的拆分与组合时,需要遵守的规则
使用什么样的语法格式来引用模块
在模块中使用什么样的语法格式向外暴露成员
node.js模块:
在node.js中根据模块来源,分为三种:
- 内置模块(在node.js中自带的模块)l例如:fs,path,http模块
- 自定义模块(用户自定义创建的js模块)
- 第三模块(由第三方开发出来的模块)
什么是模块作用域:
和函数作用域类似,在自定义模块中定义的变量,方法等成员,只能在当前模块内被访问,这种模块级别的访问限制叫做模块作用域。
向外共享模块作用域中的成员:
利用module对象:在每个.js自定义模块中都有一个module对象,它里面存储了和当前模块有关的信息
利用module.export对象:可以使用该对象将模块内的成员共享出去,供外界使用。外界用require方法导入自定义模块时,得到的就是Module.exports所指的对象
exports对象:
由于module.exports单词写起来比较复杂,为了简化向外共享成员的代码,Node提供了exports对象。默认情况下,exports和module.exports指向同一个对象,最终共享的结果,还是以module.exports指向的结果为准
exports和module.exports的使用误区:
// console.log(exports)
// console.log(module.exports)
// console.log(exports === module.exports)
// exports和moudle.exports指向的是同一个对象
// const username = "zs";
// module.exports.username = username;
exports.age = 20;
exports.sayHello = function () {
console.log("大家好!");
};
exports={
name:'fjai',
age:12
}
module.exports=exports
const username = "zs";
module.exports.username = username;
// 最终,向外共享的结果,永远都是 module.exports 所指向的对象
// 尽量不在同一个模块中使用module.exports和exports
注:永远以module.exports指向的对象为准
模块化规范:
Node.js遵循CommonJS模块化规范,CommonJS规定了模块的特性和各模块之间如何相互依赖
CommonJS规定:
- 每个模块内部,module变量代表之前模块
- module变量是一个对象,它的exports属性(即module.exports)是对外的接口
- 加载某个模块,其实是加载改模块的module.exports 属性. require()方法用于加载模块
npm与包:
包的基本概念:
Node.js中的第三方模块又叫做包
从哪里搜索包:全球最大的包共享平台
从哪里下载包:下载包的服务器
如何下载包?npm包管理工具
格式化时间的高级做法:
1.使用npm包管理工具,在项目中安装格式化时间的包moment
2.使用require()导入格式化时间的包
3.参考Moment的官方API文档对时间进行格式化
//1.导入Moment包,注意导入的名称,就是装包时候的名称
const moment = require('moment')//注意是字符串node i moment
const dt = moment().format('YYYY-MM-DD HH:mm:ss')
console.log(dt)
在项目中安装包的命令:
npm install 包的完整名称
简写形式:
npm i 包的完整名称
注意点
1.初次装包完成后,在项目文件夹下多一个叫做node_modules的文件夹和package-lock.json的配置文件,其中node_modules文件夹用来存放所有已安装到项目中的包。require()导入第三方包时,就是从这个目录中查找并加载包
package-lock.json配置文件用来记录node_modules目录下的每一个包的下载信息,例如包的版本号,下载地址等
2.安装指定版本的包:
默认情况下,会自定安装最新版本的包,如果需要安装指定版本的包,可以在包名之后,通过@符号指定具体的版本npm i moment@2.22.2
3.包的语义化版本规范
包的版本号是以“点分十进制”形式进行定义的,总共有三位数字,例如2.24.0
其中每一位数字所代表的含义如下:第一位: 大版本
第二位:功能版本第三位:bug修复版本
只要前面的版本号增长了,则后面的版本号归零
包管理配置文件:
1. 多人协作的问题:第三方的包的体积过大,不方便成员之间共享项目源代码
解决方案:共享时剔除node_modules
2. 在项目根目录中,创建一个叫做package.json的配置文件,即可用来记录在项目中安装了哪些包,从而方便剔除node_modules目录之后,在团队成员之间共享项目的源代码
今后在项目开发中,一定要把Node_modules文件夹,添加到.gitignore忽略文件夹中
3. npm包管理工具提供了一个快捷命令,可以在执行命令时所处的目录中,快速创建package.json这个包管理配置文件:
npm init -y
上述命令只能在英文的目录下运行成功!所以项目文件夹的名称一定要使用英文命名,不能出现空格。运行npm install命令安装包的时候,npm包管理工具,会自动把包的名称和版本号,记录到package.json中
4.一次性安装所有包
使用运行npm install命令,一次性安装所有安装所有的依赖包
//执行npm install 命令时,npm 包管理工具会先读取package.json中的dependencies节点
//读取到记录的所有依赖包名称和版本号之后,包管理工具会把这些包一次性的下载到项目中去
npm install
5.卸载包
使用npm uninstall 命令
//使用npm uninstall 具体的包名 来卸载包
npm uninstall moment
注:npm uninstall命令执行成功后,会把卸载的包,自动从package.json的dependencies中移除掉
解决下包速度慢的问题:
使用淘宝NPM镜像服务器
镜像:是一种文件存储形式每一个磁盘上的数据在另一个磁盘上存在完全相同的副本即为镜像切换npm的下包镜像源。下包的镜像源,指的就是下包的服务器地址
npm config get registry
npm config set registry=https://registry.npm.taobao.org/
nrm:
为了更方便的切换下包镜像源,我们可以安装nrm这个小工具,利用nrm提供的终端命令,可以快速查看和切换下包的镜像源
//通过npm包管理工具,将nrm安装为全局可用的工具
npm i nrm -g
//查看所有能用的镜像原
nrm ls
//将下包的镜像原切换为taobao镜像
nrm use taobao
包的分类:
项目包:那些被安装到项目的node_modules目录中的包,都是项目包
项目包又分为两类,分别是开发依赖包和核心依赖包
npm i 包名-D //开发依赖包(会被记录到devDependencies节点下)
npm i 包名//核心依赖包(会被记录到)
全局包:
注:在执行 npm install 命令时,如果提供了-g 参数,则会把包安装为全局包
npm i包名-g //全局安装指定的包
npm uninstall 包名-g//卸载全局安装的包
注:只要工具性质的包,才有全局安装的必要性,因为它们提供了很好的终端命令
判断某个包是否需要全局安装后才能使用,可以参考官方提供的使用说明即可
i5ting_toc小工具:
i5ting_toc是一个可以把md文档转为Html页面的小工具,使用步骤如下
//将i5ting_toc安装为全局包
npm install -g i5ting_toc
//调用,轻松实现md转换为html的功能
i5ting_toc -f 要转换的md文件路径 -o
规范的包结构:
在清楚了包的概念,以及如何下载和使用包之后,需要了解包的内部结构
一个规范的包,它的组成机构,必须符合以下要点:
- 包必须以单独的目录而存在
- 包的定级目录下要必须包含 package.json 这个包管理配置文件
- package.json 中必须包含 name ,version ,main 这三个属性,分别代表包的名字,版本号,包的入口。
开发属于自己的包:
需要实现的功能:
- 格式化时间
- 转义Html中的特殊字符
- 还原html中的特殊字符
-
时间补零
将转义和还原html的函数包含一个模块中
将 有关时间的函数包含在一个模块中
htmlEscape.js:
// 定义转义 HTML 字符的函数
function htmlEscape(htmlstr) {
return htmlstr.replace(/<|>|"|&/g, match => {
switch (match) {
case '<':
return '<'
case '>':
return '>'
case '"':
return '"'
case '&':
return '&'
}
})
}
// 定义还原 HTML 字符串的函数
function htmlUnEscape(str) {
return str.replace(/<|>|"|&/g, match => {
switch (match) {
case '<':
return '<'
case '>':
return '>'
case '"':
return '"'
case '&':
return '&'
}
})
}
module.exports = {
htmlEscape,
htmlUnEscape
}
dateFormat.js:
// 定义格式化时间的函数
function dateFormat(dateStr) {
const dt = new Date(dateStr)
const y = dt.getFullYear()
const m = padZero(dt.getMonth() + 1)
const d = padZero(dt.getDate())
const hh = padZero(dt.getHours())
const mm = padZero(dt.getMinutes())
const ss = padZero(dt.getSeconds())
return `${y}-${m}-${d} ${hh}:${mm}:${ss}`
}
// 定义一个补零的函数
function padZero(n) {
return n > 9 ? n : '0' + n
}
module.exports = {
dateFormat
}
最后将两个模块向外共享为一个封装包中对外共享
index.js:
// 这是包的入口文件
const date = require('./src/dateFormat')
const escape = require('./src/htmlEscape')
// 向外暴露需要的成员
module.exports = {
...date,
...escape
}
其package.json文件:
{
"name": "itheima-tools",
"version": "1.1.0",
"main": "index.js",
"description": "提供了格式化时间、HTMLEscape相关的功能",
"keywords": [
"itheima",
"dateFormat",
"escape"
],
"license": "ISC"
}
其README.md文档:
## 安装
```
npm install itheima-tools
```
## 导入
```js
const itheima = require('itheima-tools')
```
## 格式化时间
```js
// 调用 dateFormat 对时间进行格式化
const dtStr = itheima.dateFormat(new Date())
// 结果 2020-04-03 17:20:58
console.log(dtStr)
```
## 转义 HTML 中的特殊字符
```js
// 带转换的 HTML 字符串
const htmlStr = '<h1 title="abc">这是h1标签<span>123 </span></h1>'
// 调用 htmlEscape 方法进行转换
const str = itheima.htmlEscape(htmlStr)
// 转换的结果 <h1 title="abc">这是h1标签<span>123&nbsp;</span></h1>
console.log(str)
```
## 还原 HTML 中的特殊字符
```js
// 待还原的 HTML 字符串
const str2 = itheima.htmlUnEscape(str)
// 输出的结果 <h1 title="abc">这是h1标签<span>123 </span></h1>
console.log(str2)
```
## 开源协议
ISC
模块的加载机制:
优先从缓存中加载:
模块在第一次被加载后会被缓存。这也意味着多次调用require()不会导致模块的代码被多次执行。注意:不论是内置模块,自定义模块,还是第三方模块,它们都会优先从缓存中加载,从而提高模块的加载效率。
内置模块的加载机制:
内置模块加载优先级最高。
自定义模块的加载机制:
使用require()加载自定义模块时,必须指定以./或…/开头的路径标识符。在加载自定义模块时,如果没有指定的话,则node模块就会把他当成内置模块或者第三方模块进行加载
同时,在使用require()导入自定义模块时,如果省略了文件的拓展名,则node.js就会按顺序分别尝试加载以下的文件
1.按照确切的文件名进行加载
2.补全.js拓展名进行加载
3.补全.json拓展名进行加载
4.补全.node拓展名进行加载
5.加载失败,终端报错
第三方模块的加载机制:
如果传递给require()的模块标识符不是一个内置模块,也没有./等等开题,则Node.js会从当前模块的父目录开始,尝试从.node_modules文件夹中加载第三方模块。如果没有找到第三方模块,则移动到再上一层父目录中,进行加载,直到文件系统的根目录
目录作为模块:
当把目录作为模块标识符,传递给require()进行加载的时候,有三种加载方式:
- 在被加载的目录下查找一个叫做 package.json 的文件,并寻找 main 属性 ,作为 require()加载的入口
- 如果目录里没有package.json 文件,或从main 入口不存在或无法解析,Node.js会试图加载目录下 index.js文件
- 如果两步都失败了,则Node.js会在终端打印错误消息,报告模块的缺失:Error:Cannot find module 'xxx'
结语:
博主 node.js专栏正在持续更新中,关注博主订阅专栏学习Node不迷路!