require
方法导入所需要的模块,可定义变量赋值,此变量即可执行模块内部的方法(同步引入)1
2
3
4
5
require('module_name')
const cmd = require('module_name')
cmd.method()
cmd.prop
....
module.exports
导出所需要的模块1
2
3
4
5
6
7
8
const a = 1
const addA = () => {
a++
}
module.exports {
a,
addA
}
需要注意的是,一旦我们拿到了a的值,不管我们如何执行addA,暴露出得a的值还是为1,引用类型除外 看代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// cmd.js
let count = 1
let obj = {
size: 1
}
const addCount = () => {
count ++
console.log('addCount', count)
}
const addSize = () => {
obj.size ++
console.log('addSize', obj.size)
}
module.exports = {
count,
obj,
addSize,
addCount
}
1
2
3
4
5
6
7
8
9
// index.js
LogUtils.logInfo(cmd.count, 'CMD.count') // CMD.count 1
cmd.addCount() // addCount 2
LogUtils.logInfo(cmd.count, 'CMD.count') // CMD.count 1
LogUtils.logInfo(cmd.obj.size, 'CMD.obj.size') // CMD.obj.size 1
cmd.addSize() // addSize 2
LogUtils.logInfo(cmd.obj.size, 'CMD.obj.size') // CMD.obj.size 2
require
, exports
实现CommonJS的一个模块,就是一个脚本文件。require命令第一次加载该脚本,就会执行整个脚本,然后在内存生成一个对象
1
2
3
4
5
6
{
id: '...',
exports: { ... },
loaded: true,
...
}
id属性是模块名,exports属性是模块输出的各个接口,loaded属性是一个布尔值,表示该模块的脚本是否执行完毕。其他还有很多属性,这里都省略了。 以后需要用到这个模块的时候,就会到exports属性上面取值。即使再次执行require命令,也不会再次执行该模块,而是到缓存之中取值。
http://www.ruanyifeng.com/blog/2015/11/circular-dependency.html
通过回调函数的执行方式,执行异步操作,等到引入的模块加载完成之后才会执行回调函数的代码
define
定义函数模块require
引入函数模块在定义模块的过程中,如果定义的模块有需要引入的依赖,需要在 define 内部的回调函数之前添加模块路径地址,可以引入多个模块,使用过程中就是在回调中传入对应顺序的依赖,并为其命名,之后在回调函数内部即可访问到该模块的属性方法 格式如下
1
2
3
4
5
6
7
define(
'模块id',
['依赖数组'],
function([依赖数组]){ //工厂函数
...
}
);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// amd.js
define('add', ['./../node_modules/d-utils/lib/index.js'], function(Dutils) {
let a = 1
function getA () {
Dutils.LogUtils.logInfo(a, 'getA')
}
function addA () {
a ++
}
return {
a,
addA,
getA
}
})
同样在使用模块的时候,和define类似
1
2
3
4
5
6
7
8
9
// index.js
require(['./amd'], function(AMD) {
console.log(AMD.a)
AMD.addA()
console.log(AMD.a)
// getA
AMD.getA()
})
产生的原因是为了整合 CMD 和 AMD 的规范 使用工厂模式定义不同规范
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
(function (global, factory) {
// 判断是否支持cmd
if (typeof exports === 'object' && typeof module !== undefined) {
module.exports = factory()
} else if (typeof define === 'function' && define.amd) { // 设置amd
define('add', [], factory)
} else {
global.add = factory() // 添加至全局环境
}
})(this, function() {
let a = 1
function addA () {
a++
}
return {
a,
addA
}
})
import
导入模块export
导出模块
详细语法可以看阮老师es6的1
2
3
4
5
6
7
8
9
// add.js
export let a = 1
export const addA = function () {
a ++
}
export default {
a,
addA
}
1
2
3
4
5
6
7
8
9
10
import ADD, {
a,
addA as changeAddName
} from './module_name'
LogUtils.logInfo(a, 'Es6') // 1
ADD.addA()/
LogUtils.logInfo(a, 'Es6') // 2
changeAddName()
LogUtils.logInfo(a, 'Es6') // 3
这个和之前的cmd 的例子不一样,es6 在引入之后,修改模块的值,会使模块自身的值也发生变化 看阮老师说的 JS 引擎对脚本静态分析的时候,遇到模块加载命令import,就会生成一个只读引用。等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块里面去取值。换句话说,ES6 的import有点像 Unix 系统的“符号连接”,原始值变了,import加载的值也会跟着变。因此,ES6 模块是动态引用,并且不会缓存值,模块里面的变量绑定其所在的模块。
http://www.ruanyifeng.com/blog/2015/11/circular-dependency.html
谈谈Js前端模块化规范: https://segmentfault.com/a/1190000015991869
commmjs规范: https://www.jianshu.com/p/dd08f4095a49
JavaScript 模块的循环加载: http://www.ruanyifeng.com/blog/2015/11/circular-dependency.html
ECMAScript 6 入门: https://es6.ruanyifeng.com/
✏️ 如有问题,欢迎指正