模块化
模块化简介
Node中,一个js文件就是一个模块。
require
node使用require引入外部模块,
注意:如果要使用相对路径,必须以.或..开头
require引入模块之后会返回一个对象,该对象表示的是引入的模块。
require引入
运行命令
node helloNode.js
运行结果
module A
hello node
helloNode.js
1
2 require('./module');
console.log("hello node");
module.js
1 console.log("module A");
exports暴露变量
Node中,每个js文件中的js代码实际上都相当于运行在一个独立的函数之中。
1 | (function(){ |
可以通过exports来向外暴露变量。
1 | exports.variableName |
exports案例
helloNode.js
1 | let module_prop = require('./module'); |
module.js
1 | exports.a = 123; |
node helloNode.js
运行结果:
123 abc
15
模块化详解
模块标识
使用require引入模块的时候,使用的就是模块标识,
模块标识能用来找到指定模块。
模块标识分为两大类:
- 核心模块
- 由node引擎提供的模块
- 核心模块的表示就是模块名
1
let fs = require("fs")
- 文件模块
- 由用户自己创建的模块
- 文件模块的标识就是文件的路径(绝对路径、相对路径)
1
let math = require("./math")
全局对象global
node中有一个全局对象global,作用和window类似,
全局中创建的变量和函数都会作为global的方法和属性保存。
不使用let/var定义的变量即全局变量:
1 | let a = 10; |
node对模块的函数化包装
如何确定我们调用的js文件实际上是函数呢?
可以使用js中函数独有的arguments.callee属性,
这个属性描述的是正在调用的函数体
执行代码
1
2 let a = 10;
console.log(arguments.callee + "");
输出结果
1 | function(exports, require, module, __filename, __dirname) { |
node模块化正是对每个js模块文件中的执行代码进行函数包装操作:
1 | function(exports, require, module, __filename, __dirname){ |
这同是也解释了我们之前使用的exports和require的来源,它们都是被包装的函数传进来的参数。
- exports
- 用于将变量或函数暴露到外部
- require
- 函数,用于引入外部模块
require函数代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34[Function: require] {
resolve: [Function: resolve] { paths: [Function: paths] },
main: Module {
id: '.',
path: 'D:\\CS_Demo\\V_Demo\\NodeJs_Demo\\day2_module',
exports: {},
filename: 'D:\\CS_Demo\\V_Demo\\NodeJs_Demo\\day2_module\\main.js',
loaded: false,
children: [],
paths: [
'D:\\CS_Demo\\V_Demo\\NodeJs_Demo\\day2_module\\node_modules',
'D:\\CS_Demo\\V_Demo\\NodeJs_Demo\\node_modules',
'D:\\CS_Demo\\V_Demo\\node_modules',
'D:\\CS_Demo\\node_modules',
'D:\\node_modules'
]
},
extensions: [Object: null prototype] {
'.js': [Function (anonymous)],
'.json': [Function (anonymous)],
'.node': [Function (anonymous)]
},
cache: [Object: null prototype] {
'D:\\CS_Demo\\V_Demo\\NodeJs_Demo\\day2_module\\main.js': Module {
id: '.',
path: 'D:\\CS_Demo\\V_Demo\\NodeJs_Demo\\day2_module',
exports: {},
filename: 'D:\\CS_Demo\\V_Demo\\NodeJs_Demo\\day2_module\\main.js',
loaded: false,
children: [],
paths: [Array]
}
}
}
- module
- 代表当前模块自身
- exports就是module的属性,用exports和module.exports本质上没有区别
1
console.log(Object.is(module.exports,exports)); //true
module对象源码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15Module {
id: '.',
path: 'D:\\CS_Demo\\V_Demo\\NodeJs_Demo\\day2_module',
exports: {},
filename: 'D:\\CS_Demo\\V_Demo\\NodeJs_Demo\\day2_module\\main.js',
loaded: false,
children: [],
paths: [
'D:\\CS_Demo\\V_Demo\\NodeJs_Demo\\day2_module\\node_modules',
'D:\\CS_Demo\\V_Demo\\NodeJs_Demo\\node_modules',
'D:\\CS_Demo\\V_Demo\\node_modules',
'D:\\CS_Demo\\node_modules',
'D:\\node_modules'
]
}
- __filename
- 当前模块的完整路径
- __dirname
- 当前模块所在文件夹的完整路径
module.exports和exports的区别
对于暴露单个属性或方法,使用module.exports和exports都是一样的:
math.js
1 | exports.pi = 3.14; |
main.js
1 | let math = require('./math'); |
但是如果将需要将对象和方法包装成类暴露的话,
通过module.exports可以直接赋值,
而直接修改exports相当于修改exports的指向,切断了它和module之间的指向关系。
1 | module.exports = { |