# 模块机制

AMD,CMD,UMD,CommonJs,Es6 Modules? 啥啥啥?都是啥?傻傻分不清楚!

# CommonJs

  • 优点:
    • 同步步加载,模块加载会阻塞接下来代码的执行,需要等到模块加载完成才能继续执行
    • 就近依赖,用的时候再加载
    • 避免环境被变量污染的可能
  • 缺点:
    • 不可以在浏览器端运行
  • 特点:
    • 模块可以多次加载,但是只会在第一次加载时运行一次,然后运行结果就被缓存了,以后再加载,就直接读取缓存结果。要想让模块再次运行,必须清除缓存
  • 运行环境:Node
// 导出模块 a.js
exports.name = 'uncle-yang';

// 导出模块 b.js
var sex = 'man';

module.exports = {
    sex: sex
}

// 定义模块c
var b = require('./b.js');
var name = '大叔·杨';

if(b.sex !== 'man'){
    // 将不再加载a.js
    var a = require('./a.js');

    name = a.name;
}

module.export = {
    name: name
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# AMD

AMD(Asynchronous Module Definition),这种规范是异步的加载模块,先定义所有依赖,然后在加载完成后的回调函数中执行;其特点是

  • 优点:
    • 异步前置加载依赖(模块执行时,依赖已经加载完成)
    • 可以并行加载多个文件
  • 缺点
    • 提高开发成本
    • 不能按需加载,必须提前加载所有依赖(前置加载)
  • 运行环境:浏览器
  • 实现库:

写法例子:

//定义模块 a.js
define({
    name: 'uncle-yang'
});

//定义模块 b.js
define(function(){
    // 可以用return对外暴露
    return {
        sex: 'max'
    }
})

// 定义模块 c.js, 依赖a和b
defined(['a.js', 'b.js'], function(a, b){
    return {
        name: a.name,
        sex: b.sex,
        age: 30
    }
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# CMD

CMD (Common Module Definition),就近依赖

  • 优点:
    • 异步加载
    • 就近依赖,用的时候再加载
  • 缺点
    • 依赖spm打包,模块的加载逻辑偏重
  • 运行环境:浏览器
  • 实现库:
//定义模块 a.js
define(function(require, exports, module){
    exports.name = 'uncle-yang'
});

//定义模块 b.js
define(function(require, exports, module){
    module.exports = {
        sex: 'max'
    }

    //或者用return对外暴露
    return {
        sex: 'max'
    }
});

define(function(require, exports, module) {
    var a = require('a'),
        b = require('b');

    module.exports = {
        name: a.name,
        sex: b.sex,
        age: 30
    }
});
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

TIP

requireJS是异步加载模块,SeaJS是同步加载模块?这么理解实际上是不准确的,其实加载模块都是异步的。只不过AMD依赖前置,js可以方便知道依赖模块是谁,立即加载。而CMD就近依赖,需要使用把模块变为字符串解析一遍才知道依赖了那些模块

# UMD

UMD是创造了一种同时使用AMD和CommonJS两种规范的方法,常见写法

(function (root, factory) {
    var moduleName = 'un';

    if(typeof exports === 'object' && typeof module === 'object'){
        // commonJs
		module.exports = factory();
    }else if(typeof define === 'function' && (define.amd || define.cmd)){
        // amd & cmd
		define([], factory);
    }else{
        // 传统模式,挂载到全局
		root[moduleName] = factory();
    }
})(this, function() {
    return return {
        name: 'uncle-yang'
    }
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# Es6 module

es6自带规范

  • 优点:
    • 终于有原生支持的语法了
  • 特点
    • 导入导出必须在代码顶层
    • 只能导出对象,不能导出一个值
  • 运行环境:浏览器;但是由于浏览器兼容问题,所以只能通过babel将不被支持的import编译为require 写法:
// 分开导出:a.js
export var name = 'uncle-yang';

// 分开导出:b.js
var sex = 'man';

export {
    sex: sex
}

// 引入和导出,c.js
import a from 'a.js';
import {sex as uncleSex} from 'b.js';

/**
 * 默认导出 
 * export default命令用于指定模块的默认输出,只支持值导出,
 * 但是只能指定一个,本质上它就是输出一个叫做default的变量或方法
 */
export default {
    name: a.name,
    sex: uncleSex,
    age: 30
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
上次更新: 3/8/2019, 12:14:06 PM