Node.js中的模块化
- Node.js中根据模块来源的不同,将模块分成了三类:
分类 | 含义 |
---|---|
内置模块 | 由Node.js官方提供,例如fs、path、http等 |
自定义模块 | 即用户创建的每个.js文件 |
第三方模块 | 不属于前两者,且使用require()方法引入的包 |
- 加载模块:使用require()方法,可以加载需要的内置模块、用户自定义模块、第三方模块进行使用
- 注意:使用require()方法加载其他模块时,会直接执行被加载模块的代码
加载的模块可以省略.js的后缀名,因为node会自动尝试帮你补全
实例代码如下:
//加载内置的fs模块
const fs = require("fs")
//加载用户自定义模块:require("路径名称")
const custom = require("./custom.js")
//加载第三方模块
const moment = require("moment")
模块作用域和module对象
模块作用域:和函数作用域类似,在自定义模块中定义的变量、方法等成员,只能在当前模块内被访问,这种模块级别的访问限制,叫做模块作用域
(防止了全局变量污染的问题)-
module对象:在每个.js自定义模块中都有一个module对象,它里面存储了和当前模块有关的信息
- 在自定义模块中,可以使用module.exports对象,将模块内的成员共享出去,供外界使用
- 外界用require()方法导入自定义模块时,得到的就是module.exports所指向的对象
const age = 18 //向外暴露数据 module.exports.username = "张三" module.exports.age = age
- 注意:使用require()方法导入模块时,导入的结果,永远以 module.exports 指向的对象为准(重要的是 module.exports 地址值的指向)
-
exports对象
- 由于module.exports写起来毕竟复杂,为简化向外共享成员的代码,Node提供了exports对象。
- 默认情况下,exports和module.exports指向同一个对象。最终共享的结果,还是以module.exports指向的结果为准
-
exports和module.exports的使用误区
- 时刻谨记,require()模块时,得到的永远是module.exports指向的对象
- 为了防止混乱,建议不要在同一个模块中同时使用exports和module.exports
序 误区点 ① 当.js文件中不存在module.exports = {...}语句时,最终向外暴露的结果,module.exports.变量名指向对象的优先级,要高于exports对象的指向 ② exports.变量名 和 module.exports.变量名,都是往同一个对象赋值(一般情况下,exports和module.exports,指向的是同一个对象) -
Node.js中的模块化规范
- Node.js遵循了CommonJS模块化规范,CommonJS规定了模块的特性和各模块之间如何相互依赖
- CommonJS规定:
序 规定 ① 每个模块内部,module变量代表当前模块 ② module变量是一个对象,它的exports属性(即module.exports)是对外的接口 ③ 加载这个模块,其实是加载该模块的module.exports属性。require()方法用于加载模块
npm了解及使用
-
npm-包的概念
- 就像电脑和计算机指的是相同的东西,第三方模块和包指的是同一个概念,只不过叫法不同
- 包是基于内置模块封装出来的,提供了更高级、更方便的API,极大地提高了开发效率
- npm,Inc公司 => 包共享平台|全球最大的包共享平台:http://www.npmjs.com/
npm,Inc公司提供了一个地址为 https://registry.npmjs.org/ 的服务器,来对外共享所有的包 - npm包管理工具(Node Package Manager),这个包管理工具随着Node.js的安装包一起被安装到了用户的电脑上
序号 注意点 ① 从 http://www.npmjs.com/ 上搜索自己需要的包 ② 从 https://registry.npmjs.org/ 服务器上下载自己需要的包 npm的使用
1.使用npm安装包:npm install 包的完整名称
//简写 =>npm i 包的完整名称
2.在.js文件中引入包
//实例 =>const moment = require("moment")
3.在网站 http://www.npmjs.com/ 上搜包的名称,查看具体的文档教程。-
使用npm的注意点
npm初次装包后会多了一些配置文件
1.node_modules文件夹用来存放所有已安装到项目中的包。require()导入第三方包时,就是从这个目录中查找并加载包
2.package-lock.json配置文件用来记录 node_modules 目录下的每一个包的下载信息,例如包的名字、版本号、下载地址等不要手动修改 node_modules 或 package-lock.json 文件中的任何代码,npm包管理工具会自动维护它们
默认情况下,使用npm install 命令安装包的时候,会自动安装最新版本的包。如果需要安装指定版本的包,可以在包名之后,通过 @ 符号指定具体的版本
实例:npm i moment@2.22.0
-
包的语义化版本规范:以"点分十进制"形式进行定义,例如2.24.0
位数 语义 第一位数字: 大版本 第二位数字: 功能版本 第三位数字: Bug修复版本 注意:版本号提升规则:只要前面的版本号增加了,则后面的版本号归零
package.json文件
- npm规定,在项目根目录中,必须提供一个叫做package.json的包管理配置文件。用来记录与项目有关的配置信息
//上传源码时会删掉第三方模块的包,而package.json记录了运行源码所需要的第三方的包
- npm提供了快速创建 package.json 文件的命令:npm init -y
注意:
①该命令只能在英文的目录下成功运行
②运行 npm install 命令安装包的时候,npm包管理工具会自动把包的名称合版本号,记录到 package.json 中
-
dependencies节点
- package.json文件中,有一个dependencies节点,专门用来记录使用 npm install 命令安装了哪些包
- 执行一条命令安装多个包:npm install 包1 包2 ... 包n
1.执行 npm install(或npm i)命令,可以一次性安装所有的依赖包(dependencies节点记录的所有包)
2.运行 npm uninstall 包名 命令,可以卸载指定的包
-
devDependencies节点
- 如果某些包只在项目开发中会用到,在项目上线后不会用到,则建议把这些包记录到devDependencies节点中
安装到devDependencies指令:npm i 包名 -D | 完整写法:npm i 包名 --save-dev //后两个的参数顺序不重要
- 与之对应的,如果某些包在开发和项目上线之后都需要用到,则建议把这些包记录到dependencies节点中
切换下包的镜像源地址
- npm默认从海外的服务器下载包,此时网络数据的传输需要经过漫长的海底光缆,因此下包速度会很慢
- 淘宝NPM镜像服务器:国内搭建的一个专门同步官方包体的服务器,在国内提供下包服务,从而提高下包的速度
- 镜像:是一种文件存储形式,一个磁盘上的数据在另一个磁盘上存在一个完全相同的副本即为镜像
1 .查看当前的下包镜像源:npm config get registry
2 .重新设置当前的下包镜像源:
npm config set registry=https://registry.npm.taobao.org/
- 使用nrm切换镜像源
1.将nrm安装为全局可用的工具:npm i nrm -g
2.查看所有可用的镜像源:nrm ls
3.将下载的镜像源切换为 taobao 镜像
包的分类
- 包分为两类:①项目包 ②全局包
- 项目包又分为两类:
1 .开发依赖包(被记录到devDependencies节点中的包,只在开发期间会用到)
2 .核心依赖包(被记录到dependencies节点中的包,在开发期间和项目上线之后都会用到) - 全局包
- 在执行 npm install命令时,如果提供了 -g 参数,则会把包安装为全局包
//全局包会被安装到 C:\Users\Lenovo\AppData\Roaming\npm\node_modules - 相关指令
1 . npm i 包名 -g //全局安装指定的包
2 . npm uninstall 包名 -g //卸载全局安装的包 - 注意:
①只有工具性质的包,才有全局安装的必要性
②判断某个包是否需要全局安装才能使用,需要先去官网查看包的说明文档
- 在执行 npm install命令时,如果提供了 -g 参数,则会把包安装为全局包
- 规范的包 => 必须符合以下点要求:
①包必须以单独的目录而存在
②包的顶级目录下要必须包含 package.json 这个包管理配置文件
③ package.json 中必须包含 name,version,main 这三个属性,分别代表包的名字、版本号、包的入口(包代码的执行入口)
模块的加载机制
-
优先从缓存中加载
- 模块在第一次加载后会被缓存。这也意味着多次调用require()不会导致模块的代码被执行多次
- 注意:不论是内置模块、用户自定义模块、还是第三方模块,它们都会优先从缓存中加载,从而提高模块的加载效率
内置模块的加载优先级最高
-
自定义模块的加载机制
- 在使用require()导入自定义模块时,如果省略了文件的扩展名,则Node.js会按照顺序分别尝试加载以下的文件:
①按照确切的文件名进行加载
②补全.js扩展名进行加载
③补全.json扩展名进行加载
④补全.node扩展名进行加载
⑤加载失败,终端报错
- 在使用require()导入自定义模块时,如果省略了文件的扩展名,则Node.js会按照顺序分别尝试加载以下的文件:
-
第三方模块的加载机制
- 在一个.js文件中,对于第三方模块,node.js会从当前文件的父目录开始,尝试从 /node_modules 文件夹中加载第三方模块
- 如果没有找到对应的第三方模块,则移动到再上一层父目录中,进行加载,直到文件系统的根目录
-
把目录作为模块加载
- 当把目录作为模块标识符,传递给require()进行加载时,会执行以下步骤:
①在被加载的目录下查找一个叫做 package.json 的文件,并寻找 main 属性,来作为 reuqire() 加载的入口
②如果目录里没有 package.json 文件,或者 main 入口不存在或无法解析,则 Node.js 会试图加载目录下的 index.js 文件
③如果以上两步都失败了,则 Node.js 会在终端打印错误消息,报告模块的缺失 Error:Cannot find module 'xxx'
- 当把目录作为模块标识符,传递给require()进行加载时,会执行以下步骤: