JavaScript模块规范

JavaScript模块规范

CommonJS

Node.js和Webpack采用CommonJS编写,包括:

  • 模块引入(require),用于加载模块
  • 模块定义(exports),对外的接口,加载模块其实就是加载module.exports属性(Node中每个模块exports即为module.exports,不要对exports重新赋值,只能添加属性)
  • 模块标识(module),在模块内代表当前模块

    特点:

  • 独立作用域

  • 同步引入
  • 首次加载时require时运行,再次加载直接取缓存结果,要再次运行需要清除缓存

require命令

  • 加载并执行一个js文件,返回exports属性
  • 参数可以为绝对路径、相对路径、文件名,文件名查找顺序node安装目录->当前目录node_modules->逐级向上的node_modules
  • require.main === module,可以在模块内判断模块是直接执行(true)还是require加载执行

require源码解析

循环加载

A加载B,B又加载A,那么B加载的将是A已经执行的部分,例如:

1
2
3
4
5
6
7
8
9
// A.js
module.exports.x = 'a1';
require(./B.js); // 执行到这里就会加载B.js
module.exports.x = 'a2';

// B.js
module.exports.x = 'b1';
require(./A.js); // 执行到这里只会加载A.js在加载B.js之前已经执行的第一句,返回一个{ x: 'a1' }的对象
module.exports.x = 'b2';

AMD

Asynchronous Module Definition,异步模块定义,依赖前置原则,主要用于浏览器,RequireJS 在推广过程中对模块定义的规范化产出

定义模块

语法

[dependencies], factory)```
1
2
3
4
5
6
7
8
9
10

- id,模块标识
- dependencies,依赖的模块的名称数组,依赖前置,先解决依赖才会执行factory方法
- factory,工厂方法,初始化模块需要执行的函数或者对象,函数参数为依赖的模块,为对象时为模块的输出值

### 加载模块

需要引入require.js后使用require方法

```require([dependencies], fucntion(){})

示例

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
// base.js
define(function() {
return {
base: function() {}
}
})
// ui.js
define(['base.js'], function(base) {
return {
initPage: function() {}
}
})
// page.js
define(['base.js', 'ui.js'], function(base, ui) {
// ...
})
// data.js
define({
users: [],
numbers: []
})
// 兼容CommonJS规范
define(function(require, exports, module) {
var base = require('base.js');
module.exports.show = function() {};
})

CMD

Common Module Definition,通用模块定义,依赖就近原则,是SeaJS 在推广过程中被广泛认知。

定义模块

语法

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

- factory,可以为字符串、对象、函数等
- 为函数时就是模块的构造方法,function(require, exports, module) {}
- 构造方法内require为同步加载,require.async(dependencies, function(){})为异步加载

## UMD

兼容CommonJS和AMD规范

## ES6

- 静态化,ES6在编译时确定依赖关系而不是CommonJS和AMD的运行时,所以引入是不能是表达式
- ES6的模块并不返回一个对象,通过export和import导出和引入
- 提升效果,可以在引入前使用

```javascript
// CommonJS
let { aaa, bbb } = require('math');
// 相当于
let tmp = require('Math');
let aaa = require.aaa;
let bbb = require.bbb;

// ES6
import { aaa, bbb } from 'math';
// aaa, bbb必须和模块中导出的变量同名
// export和import时都可以使用as对变量重命名,使用*表示整个模块

// 模块内使用export default匿名导出,引用时可以自己命名模块
import anyname from 'math';

0%