N o d e J s 中 的 模 块 化 \color{blue}{NodeJs中的模块化} NodeJs中的模块化
Node 应用由模块组成,采用 CommonJS 模块规范。
CommonJS 就是模块化的标准, nodejs 就是 CommonJS( 模块化) 的实现。 ✌️✌️✌️
-
模
块
的
分
类
:
\color{navy}{模块的分类:}
模块的分类:
- 核心模块
- 核心模块指的是那些被编译进Node的二进制模块
- 预置在Node中,提供Node的基本功能,如fs、http、https等
- 核心模块使用C/C++实现,外部使用JS封装
- 文件模块
- 文件可放在任何位置
- 加载模块文件时加上路径即可
- 第三方模块
- Node使用npm(Node Package Manager)安装第三方模块
- npm会将模块安装(可以说是下载到)到应用根目录下的node_modules文件夹中
- 模块加载时,node会先在核心模块文件夹中进行搜索,然后再到node_modules文件夹中进行搜索
- 文件夹模块
- Node首先会在该文件夹中搜索package.json文件
- 存在,Node便尝试解析它,并加载main属性指定的模块文件
- 不存在(或者package.json没有定义main属性),Node默认加载该文件夹下的index.js文件(main属性其实NodeJS的一个拓展,CommonJS标准定义中其实并不包括此字段)
- 文件夹模块的例子
-
在根目录下的
/main.js
中,我们需要使用一个自定义文件夹模块。 -
将所有的自定义文件夹模块存放在根目录下的
/module
下,其中有一个/module/demo
文件夹,是我们需要引入的文件夹模块; -
文件夹目录
|——main.js
|——module
\qquad |—— demo
\qquad\qquad |—— package.json
\qquad\qquad |—— demo.js -
package.json
文件的信息如下:{ "name": "demo", "version": "6.0.0", "main": "./demo.js" }
-
在
main.js
中:let demo = require("./modules/demo");
-
Node将会根据
package.json
中指定的main属性,去加载./module/demo/demo.js
-
这就是一个最简单的包,以一个文件夹作为一个模块。✌️✌️✌️
-
- Node首先会在该文件夹中搜索package.json文件
- 核心模块
-
C
o
m
m
o
n
J
S
(
N
o
d
e
j
s
)
中
自
定
义
模
块
的
规
定
:
\color{navy}{CommonJS( Nodejs) 中自定义模块的规定:}
CommonJS(Nodejs)中自定义模块的规定:
- 我们可以把公共的功能抽离成为一个单独的 js 文件作为一个模块, 默认情况下面这个模块里面的方法或者属性, 外面是没法访问的。如果要让外部可以访问模块里面的方法或者属性, 就必须在模块里面通过 exports 或者 module.exports 暴露属性或者方法。
- 在需要使用这些模块的文件中, 通过 require 的方式引入这个模块,这个时候就可以使用模块里面暴露的属性和方法。 ✌️✌️✌️
- 我们可以把公共的功能抽离成为一个单独的 js 文件作为一个模块, 默认情况下面这个模块里面的方法或者属性, 外面是没法访问的。如果要让外部可以访问模块里面的方法或者属性, 就必须在模块里面通过 exports 或者 module.exports 暴露属性或者方法。
-
C
o
m
m
o
n
J
S
定
义
的
模
块
分
为
:
\color{navy}{CommonJS定义的模块分为: }
CommonJS定义的模块分为:
- 模块引用(require)
- 模块定义(exports)
- 模块标识(module)
-
定
义
使
用
模
块
\color{navy}{定义使用模块}
定义使用模块
1.新建文件test.js,代码如下:
//模块定义
var tools = {
sayHello: function() {
return 'hello World!';
},
add: function(x, y) {
return x + y;
}
};
// 模块接口的暴露
//方法一
module.exports = tools;
//方法二
//exports.sayHello = tools.sayHello;
//exports.add = tools.add;
2.新建文件common.js,代码如下:
//模块的引用
const tools = require('./test'); //引用自定义的模块时, 在同一个目录下用 "./"
const http = require('http'); //引入http模块
const hostname ='127.0.0.1'; //服务器地址
const port = 8888; //服务器的端口号
const server = http.createServer((request,response)=>{ //使用http来创建服务器
response.statusCode=200;
if(request.url!=='/favicon.ico'){
response.setHeader('Content-Type','text/html;charset=utf-8');
//模块的调用
response.write("<br/>"+tools.sayHello()+"<br/>");
//write()函数的参数必须是字符串类型
response.write(tools.add(15,26).toString());
response.end();
}
});
//监听
server.listen(port,hostname,()=>{
console.log(`Server running at http://${hostname}:${port}/`);
});
3.浏览器访问:localhost:8888
4.结果:hello World!
41
✌️✌️✌️
包 管 理 工 具 \color{blue}{包管理工具} 包管理工具
node.js是基于CommonJS的规范实现的,npm大家一定都很熟悉,它实践了CommonJS的包规范。
-
包
规
范
\color{navy}{包规范}
包规范
关于包规范,类比于git仓库,我们可以这么理解:- git init在当前文件夹中生成了隐藏文件.git,我们把它叫做git仓库。
- npm init命令在当前文件夹中生成了配置文件package.json,它描述了当前这个包,我们管这个文件叫做包(概念不准确,可以这么理解)。
-
包
结
构
\color{navy}{包结构}
包结构
严格按照CommonJS规范来的话,包的目录应当包含以下文件或目录。- package.json:包描述文件,存在于包顶级目录下。是一个配置文件,它描述了包的相关信息。
- bin:存放可执行二进制文件的目录
- lib:存放js代码的目录
- doc:存放文档的目录
-
m
o
d
u
l
e
属
性
\color{navy}{module属性}
module属性
- m o d u l e . i d \color{aqua}{module.id} module.id 模块的识别符,通常是带有绝对路径的模块文件名。
- m o d u l e . f i l e n a m e \color{aqua}{module.filename} module.filename 模块的文件名,带有绝对路径。
- m o d u l e . l o a d e d \color{aqua}{module.loaded} module.loaded 返回一个布尔值,表示模块是否已经完成加载。
- m o d u l e . p a r e n t \color{aqua}{module.parent } module.parent 返回一个对象,表示调用该模块的模块。
- m o d u l e . c h i l d r e n \color{aqua}{module.children} module.children 返回一个数组,表示该模块要用到的其他模块。
-
m
o
d
u
l
e
.
e
x
p
o
r
t
s
\color{aqua}{module.exports}
module.exports 表示模块对外输出的值。
案例-
新建文件夹Node:
mkdir Node
-
终端进入文件夹:
cd Node
-
安装jquery来做测试:
npm install jquery
-
新建js文件:
touch jquery.js
|— —Node
\qquad |— —node_module
\qquad |— —package.json
\qquad |— —jquery.js -
jquery文件代码如下:
var jquery = require('jquery'); exports.$ = jquery; console.log(module); //module就是当前模块内部中的一个对象,代表当前对象
-
终端执行:
node jquery
-
终端命令行输出的信息如下所示:
Module { id: '.', //模块的识别符,通常是带有绝对路径的模块文件名 exports: { '$': [Function] }, //表示模块对外输出的值 parent: null, //返回一个对象,表示调用该模块的模块 filename: '/Users/anna/Node/jquery.js', // 模块的文件名,带有绝对路径 loaded: false, // 返回一个布尔值,表示模块是否已经完成加载 children: //返回一个数组,表示该模块要用到的其他模块 [ Module { id: '/Users/anna/Node/node_modules/jquery/dist/jquery.js', exports: [Function], parent: [Circular], filename: '/Users/anna/Node/node_modules/jquery/dist/jquery.js', loaded: true, children: [], paths: [Array] } ], paths: [ '/Users/anna/Node/node_modules', '/Users/anna/node_modules', '/Users/node_modules', '/node_modules' ] }
可以看到,当前这个模块的parent属性为null,这证明当前这个模块是一个入口脚本,
如果在jquery.js中引入别的文件模块,module会输出什么??? ??? -
新建js文件:
child.js
-
child.js里面的代码如下:
var str = "I'm NodeJs"; exports.str = str; console.log(module);
-
修改jquery.js中的代码:
var jquery = require('jquery'); var child=require('./child'); //在jquery中引入child模块 exports.$ = jquery; console.log(module);
-
终端继续执行:
node jquery
-
终端命令行输出的信息如下:
Module { id: '/Users/anna/Node/child.js', exports: { str: 'I\'m NodeJs' }, parent: Module { id: '.', exports: {}, parent: null, filename: '/Users/anna/Node/jquery.js', loaded: false, children: [ [Module], [Circular] ], paths: [ '/Users/anna/Node/node_modules', '/Users/anna/node_modules', '/Users/node_modules', '/node_modules' ] }, filename: '/Users/anna/Node/child.js', loaded: false, children: [], paths: [ '/Users/anna/Node/node_modules', '/Users/anna/node_modules', '/Users/node_modules', '/node_modules' ] } Module { id: '.', exports: { '$': [Function] }, parent: null, filename: '/Users/anna/Node/jquery.js', loaded: false, children: [ Module { id: '/Users/anna/Node/node_modules/jquery/dist/jquery.js', exports: [Function], parent: [Circular], filename: '/Users/anna/Node/node_modules/jquery/dist/jquery.js', loaded: true, children: [], paths: [Array] }, Module { id: '/Users/anna/Node/child.js', exports: [Object], parent: [Circular], filename: '/Users/anna/Node/child.js', loaded: true, children: [], paths: [Array] } ], paths: [ '/Users/anna/Node/node_modules', '/Users/anna/node_modules', '/Users/node_modules', '/node_modules' ] }
-
总结
child.js
中的parent属性输出的是jqueryTest.js
的module信息,- 而
jqueryTest.js
中的children属性,包括了jquery和child.js两个module信息 jqueryTest.js
中的parent属性为null;-
S
o
\color{red}{So}
So,我们可以以module.parent来判断当前模块是否是入口脚本
✌️✌️✌️✌️✌️✌️
-