文章目录
一、模块化的基本概念
1.1什么是模块化
模块化是指解决一个复杂问题时,自顶向下逐层把系统分成若干模块的过程。对于整个系统来说,模块是可组合、分解和更换的单元。
1.现实生活中的模块化
2.编程领域的模块化
编程领域中的模块化就是,遵守固定的规则,把一个大文件拆成独立并相互依赖的多个模块。
模块化的好处:
(1)提高了代码的复用性
(2)提高了代码的可维护性
(3)可以实现按需加载
1.2模块化规范
就是对代码进行模块化的拆分和组合时,需要遵守的那些规则。
例如:
使用什么样的语法格式来引用模块
在模块中使用什么样的语法格式向外暴露成员
模块饭规模的好处:降低沟通成本,方便各个模块之间的相互调用
二、Node.js中模块的分类
2.1分类
- 内置模块(内置模块是由Node.js官方提供的,例如fs,path,http)
- 自定义模块(用户创建的每个.js文件,都是自定义模块)
- 第三方模块(由第三方开发出来的模块,并非官方提供的内置模块,也不是用户创建的内置模块,使用前需要先下载)
2.2加载模块
使用强大的require()方法,可以加载需要的内置模块,用户自定义模块、第三方模块进行使用。例如:
注意:使用require()方法加载其他模块时,会执行被加载模块中的代码。
const m1 = require('./05.m1')
console.log(m1)
2.3Node.js中的模块作用域
1.什么是模块作用域
和函数作用域类似,在自定义模块中定义定义的变量、方法等成员,只能在当前模块内被访问,这种模块级别的访问限制,叫做模块作用域。
2.模块作用域的好处
防止了全局变量污染的问题
建立08js
const username = '张三'
function sayHello(){
console.log('大家好,我是' + username)
}
建立09
const custom = require('./08模块作用域')
console.log(custom)
输不出张三,username具有作用域
2.4向外共享模块作用域中的成员
1.module对象
在每个.js自定义模块中都有一个module对象,他里面存储了和当前模块相关的信息
2.moudle.exports对象
在自定义模块中,可以使用module.exports对象,讲模块内的成员共享出去,供外界使用。
//在一个自定义模块中,module.exports = {}
// 向module.exports对象上挂载username 属性
module.exports.username = 'zs'
module.exports.sayHello = function(){
console.log("Hello!")
}
3.共享成员时的注意点
使用require()方法导入模块时,导入的结果,永远以module.exports指向的对象为准。
4.exports对象
由于module.exports单词写起来比较复杂,为了简化向外共享成员的代码,Node提供了exports对象,默认情况下,exports喝module.exports指向同一个对象。最终共享的结果,还是以module.exports指向的对象为准。
!!
时刻谨记
require()模块时,得到的永远是module.exports指向的对象
2.5Node.js中的模块化规范
Node.js遵循了CommonJS模块规范,规定了模块的特性喝各模块之间如何相互依赖。
其规定:
(1)每个模块内部,module变量代表当前模块
(2)module变量是一个对象,它的export属性,即(module.exports)是对外的接口。
(3)加载某个模块,其实是加载模块的module.exports属性
三、npm与包
1.包
1.包的定义
Node.js中的第三方模块又叫做包
2.包的来源
不同于Node.js中的内置模块于自定义模块,包是由第三方个人喝团队开发出来的免费供所有人使用。
3.为什么需要包
由于Node内置模块提供了一些底层的API,导致在基于内置模块进行项目开发时,效率很低。
包是基于内置模块封装出来的提供了更高级的API提高开发效率
包喝内置模块之间的关系,类似jQuery和API之间的关系
4.下载
https://www.npmjs.com/全球最大的包共享平台
此公司提供http://registry.npmjs.org/的服务器,来对外共享所有的包,我们可以从这个服务器上下载自己需要的包
下载包需要包管理工具Node Package Manager(简称npm包管理工具)
通过npm-v在终端查看包管理工具的版本
3.2npm初体验
1.格式化时间的传统做法
自定义函数
// 定义格式化时间的方法
function dataFormat(dtStr){
const dt = new Date(dtStr)
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}`
return `${y}-${m}-${d} ${hh}:${mm}:${ss}`
}
//定义补零函数
function padZero(n){
return n > 9 ? n : '0' + n
}
module.exports = {
dataFormat
}
将函数暴露给外面
//导入自定义格式化时间的模块
const TIME = require('./15date')
// 调用方法,进行时间的格式化
const dt = new Date()
// console.log(dt)
const NEWdt = TIME.dataFormat(dt)
console.log(NEWdt)
进行调用
2.格式化时间的高级做法
(1)使用npm包管理工具,在项目中安装格式化时间的包moment
(2)使用require()导入格式化时间的包
(3)参考moment的官方API文档对时间进行格式化
const moment = require('moment')
const dt = moment().format('YYYY-MM-DD HH:mm:ss')
console.log(dt)
3.在项目中安装包的命令
如果想要在项目中安装指定名称的包,需要如下命令:
npm install 包的完整名称
简写
npm i 包名
❤️打开项目终端npm i moment在这个过程中可能会出现问题,解决了半年,最后发现是npm与node版本不匹配
👊后来出现在系统上禁止运行,出现权限问题,我们需要在系统上运行脚本
输入如下命令
get-ExecutionPolicy
输出:
Restricted
表明受限制
我们给出权限
输入:Set-ExecutionPolicy -Scope CurrentUser
然后输入:RemoteSigned
终于可以啦
❤️❤️
4.初次装包后多了哪些文件
初次装包完成后,在项目文件夹下多了一个叫做node_modules的文件夹和package-lock,json的配置文件
其中:
node_modules用来存放所有安装到项目中的包。require()导入第三时,就是从这个目录中查找并加载包。
package-lock,json用来记录node-modules目录下的每一个包的下载信息,例如包的名字,版本号,下载地址
5.安装指定版本的包
默认情况下,会安装最新版本的包,如果需要安装指定版本的饿包,可以在包名之后,通过@符号指定具体的版本,
6.包的语义化版本规范
包的版本号是以"点分十进制"形式进行定义的,总共有三位数字,例如2.24.0
其中每一位数字代表
第一位数字:大版本
第二位数字:功能版本
第三位数字:Bug修复版本
版本号提升的规则只要前面的版本好增长了,后面的版本号归零
3.3包管理配置文件
npm规定,在项目的根目录中,必须提供一个叫package.json的包管理配置文件。
用来记录与项目有关的一些配置信息
- 项目的名称、版本号、描述等
- 项目中都用到啦哪些包
- 哪些包旨在开发期间会用到
- 哪些包在开发和部署时都需要
1.多人协作开发的问题
第三方包的体积过大,不方便团队成员之间共享项目源码
解决方案:共享时删除node_modules
2.如何在项目中记录安装了哪些包
在项目根目录中,创建一个叫做package.json的配置文件,即可用来记录项目中安装了哪些包。从而方便提出node-modules目录之后,在团队成员之间共享项目的代码
3.快速创建package.json
npm包管理工具提供了一个快捷命令,可以在执行命令时所处的目录中,快速创建package.json这个包管理配置文件;
npm init -y
注意:
(1)上述命令只能在英文的目录下成功运行!所以,项目文件夹的名称一定要使用英文全名,不要使用中文,不要出现空格
(2)运行npm install命令安装包时,npm包管理工具会自动把包的名称和版本号,记录到package.json中。
4.dependencies节点
专门用来记录使用 npm install安装了哪些包
5.一次性安装所有的包
当我们拿到了一个删除了node-modules的项目之后,需要先把所有的包下载到项目中,才能将项目运行起来。
否则会报类似于下面的错误
可以运行npm install命令一次性安装所有的包
//执行npm install 命令时,npm包管理工具会先读取package.json中的dependencies节点,读取到记录的所有包依赖名称和版本号之后,npm包管理工具会把这些包一次性下载到项目中
npm install
6.卸载包
可以运行npm uninstall 命令,来卸载指定的包
npm uninstall moment
当执行成功后,会自动从package.json的dependencies中移出掉
7.devDependencies节点
如果某些包只在项目开发阶段会用到,在项目上线之后不会用到,则建议把这些包记录到devDependencies节点中
3.4解决下包速度慢的问题
1.为什么下包速度慢
在使用npm下包时,默认从国外的服务器进行下载,此时,网络数据的传输需要经过漫长的海底光缆,因此下包速度可能会很慢。
2.淘宝NPM镜像服务器
淘宝在国内搭建了一个服务器,专门把国外官方服务器上的包同步到国内的服务器,然后再国内提供下包的服务。
从而极大的提高了下包的速度。
❤️镜像❤️:是一种文件存储形式,一个磁盘上的数据在另一个磁盘上存在一个完全相同的副本即为镜像。
3.切换npm下包镜像源
下包的镜像源,指的就是下包的服务器地址
在终端切换下包地址(cmd)
#查看当前的下包镜像源
npm config get registry
#将下包的镜像切换为淘宝镜像源
npm config set registry=https://registry.npm.taobao.org/
#检查镜像源是否下载成功
npm config get registry
4.nrm
为了更方便的切换下包的镜像源,我们可以安装nrm这个小工具,利用nrm提供的终端命令,可以快速查看和切换下包的镜像源。
#通过npm 包管理工具,将nrm 安装为全局可以的工具
npm i nrm -g(cmd终端运行)
#查看所有可用的镜像源
nrm ls
#将下包的镜像源切换为taobao
nrm use taobao
3.5包的分类(i5ting_toc)
1,项目包
把那些安装到项目的node_modules目录中的包,都是项目包
项目包又分为两类,分别是:
- 开发依赖包只在开发期间会用到
- 核心依赖包在开发期间和项目上线之后都会用到
2.全局包
在执行npm install命令时,如果提供了 -g参数,则会把包安装为全局包
全全局包默认安装到C:\Users\lenovo\AppData\Roaming\npm\node_modules目录下
注意:
只要全局性质的包,才有全局安装的必要性
⭐⭐3.i5ting_toc
❤️❤️是一个可以把md文档转换为html页面的小工具,使用步骤
3.6规范的包结构
在清除了包的概念、以及如何下载和使用包之后,接下来我们深入了解一下
包的内部结构
一个规范的包,它的组成结构,必须符合以下3点要求:
(1)包必须以单独的目录存在
(2)包的顶级目录下要必须包含package.json这个包管理配置文件
(3)package.json中必须包含name,version,main这三个属性,分别是包的名字,版本号,包的入口
3.7 开发属于自己的包
1.需要实现的功能
(1)格式化日期
(2)转移HTML中的特殊字符
(3)还原HTML中的特殊字符
2.初始化包的基本结构
(1)新建my-tools文件夹,作为包的根目录
(2)在my-tools文件夹中,新建
- package.json(包管理配置文件)
- index.js(包的入口文件)
- README.md(包的说明文档)
3.初始化package.json
{
"name": "faith-tools",
"version": "1.0.0",
"main": "index.js",
"description": "提供了格式化时间、HTMLEscape相关的功能",
"keywords":[
"faith",
"dateFormat",
"escape"
],
"license": "ISC"
}
4.在index.js中定义格式化时间的方法
// 这是包的入口文件
// 定义格式化时间的函数
function dataFormat(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 = {
dataFormat
}
5.在index.js中定义转移HTML的方法
function padZero(n){
return n > 9 ? n : '0' + n
}
// 定义转移HTML字符的函数
function htmlEscape(htmlstr){
return htmlstr.replace(/<|>|"|&/g,match =>{
switch(match){
case '<':
return '<'
case '>':
return '>'
case '"':
return '"'
case '&':
return '&'
}
})
}
6.在index.js中还原HTML的方法
function htmlUnEscape(str) {
return str.replace(/<|>|"|&/g, match => {
switch (match) {
case '<':
return '<'
case '>':
return '>'
case '"':
return '"'
case '&':
return '&'
}
})
}
7.将不同的功能进行模块化拆分
(1)将格式化时间的功能,拆分到src -> dateFormat.js
(2)将处理HTML字符串的功能,拆分到src -> htmlEscape.js中
(3)在index.js中,导入两个模块,得到需要向外共享的方法
(4)在Index.js中,使用module.exports把对应的方法共享出去
8.编写包的说明文档
方便用户参考
3.8发布包
1.注册npm账号
(1)访问https://www.npmjs.com/网站,点击sign up,进入注册页面
(2)填写信息Full Name,Public Email == Username==、Password
2.登录npm账号
npm账号注册完成后,可以在终端执行npm login命令,依次输入用户名、密码、邮箱后,即可登录成功
注意:在运行npm login命令之前,必须先把下包的服务器地址切换为npm的官方服务器否则会导致发布包错误
3.把包发布到npm上
将终端切换到包的根目录之后,运行npm publish命令,即可发布
4.删除已发布的包
运行npm unpublish包名 --force命令,即可从npm删除已发布的包。
注意:
(1)npm unpublish 命令只能删除72小时以内的包
(2)npm unpublish删除的包,在24小时之内不允许重新发布
(3)发布包的时候要慎重,不要忘npm上发布没有意义的包
四、模块的加载机制
4.1优先从缓存加载
模块在第一次加载后会被缓存,这也意味着多次require()不会导致模块的代码被执行多次。
注意:不论是内置模块,用户自定义模块,还是第三方模块,它们都会优先从缓存中加载,从而提高模块的加载效率。
4.2内置模块的加载
内置模块是由Node.js官方提供的模块,内置模块的加载优先级最高。
如果第三方模块与内置模块同名,优先加载内置模块。
4.3自定义模块的加载机制
使用require()加载自定义模块时,必须指定以./或…/开头的路径标识符。在加载自定义模块时,如果没有指定./或…/这样的路径标识符,则node会把它当作内置模块或第三方模块进行加载。
同时,在使用require()导入自定义模块时,如果省略了文件的扩展名,则Node.js会按顺序分别尝试加载以下的文件:
(1)按照确切的文件名进行加载
(2)补全.js扩展名进行加载
(3)补全.json扩展名进行加载
(4)补全.node扩展名
(5)加载失败,终端报错
4.4第三方模块的加载机制
如果传递给require()的模块标识符不是一个内置模块,也没有以‘./‘或’…/'开头,则Node.js会从当前模块的父目录开始,尝试以/node_modules文件夹中加载第三方模块。
如果没有找到对应地第三方模块,则返回再上一层父目录中,进行加载,知道文件系统的根目录。
4.5目录作为模块
把目录作为模块标识符,传递给require()进行加载,有三种加载方式:
(1)在被加载的目录下查找下一个叫做package.json的文件,并寻找main属性,作为require()加载的入口
(2)如果目录种没有package.json或者main()入口不存在或者无法解析,则加载index.js文件
(3)如果上述都不行,则在终端打印错信息