Node.js:模块 & 包
模块
模块化是指解决一个复杂问题时,自顶向下逐层把系统划分成若干模块的过程。对于整个系统来说,模块是可组合、分解和更换的单元。
简单来说,就是把一个大问题拆分成一系列小问题,然后逐个解决的过程。这就像是搭乐高积木,不是直接建造一个巨大的城堡,而是先建造城堡,花园等几个小部分,然后再把它们组合起来。
如果后续某些功能不需要了,或者某些功能需要更新,只需要操作对应的模块即可,不需要改动整个程序。
再比如说,可能两个程序需要一个相同的功能,那么就就可以把这个模块复制两份,给不同的程序使用。
所以模块可以提高代码的复用性,可维护性。
Node.js
中根据模块来源的不同,将模块分为了3 大类:
- 内置模块:内置模块是由
Node.js
官方提供的,例如fs
、path
、http
等 - 自定义模块:用户创建的每个
js
文件,都是自定义模块 - 第三方模块:由第三方开发出来的模块,使用前需要先下载
想要加载一个模块,可以使用require
方法:
javascript
const obj = require('模块名')
const obj = require('模块路径')
对于内置模块和第三方模块,只需要传入模块名即可,如果是自定义模块,就需要填入模块的路径。
比如:
javascript
const test = requits('./test.js')
自定义模块一定是一个.js
结尾的文件,所以也可以省略.js
后缀:
javascript
const test = requits('./test')
模块被导入时,模块内部的代码会立刻执行一次。
./test.js
写入以下代码:
javascript
console.log('require test.js success')
在另一个文件中导入模块:
javascript
const test = require('./test.js')
console.log(test)
输出结果:
javascript
require test.js success
{}
在./test.js
中的代码,就立刻执行了一次,test
变量拿到了一个空对象。
module对象
在模块中定义的变量、方法,都只能在模块内部被访问,这种模块级别的访问限制,称为模块作用域
。
那么外部导入模块后,又要如何访问模块的内容?这就需要通过module
对象了。
在每一个.js
模块中,都有一个module
对象,这里面存储了当前模块的相关信息。
直接console.log
输出这个对象:
javascript
{
id: '.',
path: 'D:\\code_web\\test\\Node\\02',
exports: {},
filename: 'D:\\code_web\\test\\Node\\02\\main.js',
loaded: false,
children: [],
paths: [
'D:\\code_web\\test\\Node\\02\\node_modules',
'D:\\code_web\\test\\Node\\node_modules',
'D:\\code_web\\test\\node_modules',
'D:\\code_web\\node_modules',
'D:\\node_modules'
],
[Symbol(kIsMainSymbol)]: true,
[Symbol(kIsCachedByESMLoader)]: false,
[Symbol(kIsExecuting)]: true
}
可以看到一些文件的相关信息,其中exports: {}
是一个空对象,通过exports
这个属性可以向外共享模块的内容,默认情况为空。当外界通过require
导入模块时,拿到的就是这个对象。
示例:
在test.js
中,将成员与方法添加到module.exports
中:
javascript
console.log('require test.js success')
module.exports.username = "张三"
module.exports.sayHello = function(){
console.log(this.username + " say hello")
}
在main.js
中导入模块,并调用函数:
javascript
const test = require('./test.js')
console.log(test)
test.sayHello()
输出结果:
javascript
require test.js success
{ username: '张三', sayHello: [Function (anonymous)] }
张三 say hello
此时test
变量,拿到的就是一个有内容的对象,并且可以正常调用模块内的属性与方法。
每次共享一个新的成员或方法,都要使用module.exports
,这有点麻烦了。为此Node.js
提供了exports
对象,它与module.exports
指向同一个对象,在编写代码时,可以使用简写。
javascript
exports.username = "张三"
exports.sayHello = function(){
console.log(this.username + " say hello")
}
但是要注意,不要改变exports
指向的对象。
javascript
exports = {
username: "李四",
sayHello: function(){
console.log(this.username + " say hello")
}
}
如果在某个模块内部这样写,等到模块导入后,拿到的是一个空对象,而不是exports
指向的对象。因为以上代码相当于把exports
指向了一个新的对象,此时module.exports
和exports
指向不同,导入模块最终以module.exports
为准,所以exports
就失效了。
包
在Node.js
中,第三方模块又称为包
。
Node.js
的内置模块功能较少,基于内置模块开发效率很低,因此很多第三方封装了更加高级方便的模块,并公开给大家使用。
npm
如果包太多,那么每个不同的包都要去不同的地方下载,这样很麻烦。但是npm
建立了一个包共享平台,很多程序员都会把自己封装的包提交到这个平台,因此我们就可以通过npm
来快速下载所需的包。
官方网址:
javascript
https://www.npmjs.com/
安装包
下载包的命令:
bash
npm install 包名
npm i 包名
i
是install
的简写,两种格式都可以下载包。
删除包的命令:
bash
npm uninstell 包名
下载一个moment
包:
这个包是一个时间相关的包,使用时直接以普通模块的形式导入即可:
javascript
const moment = require('moment')
const dt = moment().format('YYYY-MM-DD HH:mm:ss')
console.log(dt)
此处moment().format('YYYY-MM-DD HH:mm:ss')
,用于格式化输出当前时间。
输出结果:
javascript
2024-10-30 20:40:36
配置文件
在第一次装包后,同级目录会出现以下文件:
node_modules
存储了所有下载的包,比如刚下载的moment
,而.package-lock,json
是包的相关信息,内容如下:
javascript
{
"name": "02",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"dependencies": {
"moment": "^2.30.1"
}
},
"node_modules/moment": {
"version": "2.30.1",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz",
"integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==",
"license": "MIT",
"engines": {
"node": "*"
}
}
}
}
这里面保存了下载的包的相关信息,比如下载版本,下载来源等等。
如果想要下载指定版本的包,语法如下:
bash
npm install 包名@版本号
npm i 包名@版本号
例如安装moment:2.22.2
版本:
显示修改了一个包,也就是之前的2.30.1
版本被覆盖了。
除去node_modules
和.package-lock,json
,还可以找到一个package,json
文件:
这个文件与node_modules
同级,内部包含dependencies
属性:
javascript
{
"dependencies": {
"moment": "^2.30.1"
}
}
比如再下载一个jQuery
:
此时package,json
文件更新:
javascript
{
"dependencies": {
"jquery": "^3.7.1",
"moment": "^2.30.1"
}
}
这里记录了所有下载过的包,当拿到一个项目时,往往不会提供node_modules
目录,因为这个目录很大,不利于传输。因此会提供一个package,json
文件,这个文件可以帮助快速下载所有依赖的包。
bash
npm install
npm i
当npm install
不带任何包名,就会去下载package,json
文件中指定的所有包,快速初始化项目。
package,json
文件不在node_modules
目录内部,而是与node_modules
同级,就是因为多人协作时node_modules
往往不会发送给同事,而是发送package,json
来初始化项目。
镜像源
默认情况下,npm
会去https://registry.npmjs.org/
这个网址下载包,但是这是一个国外的网址,下载速度比较慢。
为此,淘宝在国内建立了一个镜像站https://registry.taobao.org/
,这个网站会实时同步https://registry.npmjs.org/
,所以国内用户可以修改镜像源为这个淘宝的镜像源,提升下载效率。
查看当前镜像源:
bash
npm config get registry
安装nrm
工具:
bash
npm i nrm -g
查看可用的镜像源:
bash
nrm ls
切换到淘宝镜像源:
bash
nrm use taobao
分类
包分为项目包
与全局包
:
项目包
:只供一个项目使用的,安装到node_modules
目录下的包全局包
:主机上所有项目都可以使用的包
如果想要安装或卸载全局包,只需要加上-g
参数即可:
bash
npm i -g 包名
npm uninstall -g 包名
先前安装的nrm
,就是按照全局安装的,这样后续所有项目下载包时,都会使用淘宝的镜像源。