天天看点

前端模块化总结:CommonJS、CMD、AMD、ES6模块化

1. 模块化

1.1 不使用模块化的问题

全局变量污染:代码中的函数必须是全局变量,才能暴露给对方

变量重名:不同文件中的变量如果重名,后面的会覆盖前面的,造成程序运行错误。

文件依赖问题:不知道引用的文件里面会引用什么文件:互相依赖关系不清晰

不利于多人协作开发

1.2 使用模块化

— 每个文件作为一个模块,通过固定的方式向外暴露,也通过固定的方式引入外部模块

  • 只需引用一个 js 文件,其它的根据依赖关系自动引用
  • 无全局变量污染

1.3 闭包

在模块化概念提出以前,大部分会用闭包解决变量重名和全局变量污染问题,

每个js文件都用IIFE包裹,各个js文件分别在不同的此法作用域中,相互隔离,通过闭包暴露变量;

通过script标签进行引用,标签的顺序就是模块的依赖关系。

举个栗子:

//name.js

var name = 'lucy';
return name;
           

//info.js

var info = (function(name){
    var word = 'hello' + name;
    var age = 12;
    return {
        word: word,
        age: age
    }
})()
           

//word.js

var word = (function(info){
    var word = info.word + 'hello word';
    return word;
})()
           

//index.js

;(function(info, message){
    console.log('message:', message);
    console.log('age:', info.age);
})()
           
<script src='./name.js'></script>
<script src='./info.js'></script>
<script src='./word.js'></script>
           

特点:

各个js文件有自己的作用域,避免了变量重名干扰,将变量统一暴露出来,避免全局污染;

模块外部不能轻易改变闭包内部的变量,有利于程序稳定性;

模块与外部的连接通过IIFE传参,更清晰的看出依赖关系;

应对应依赖关系来决定script标签的引用顺序。

但这并不算是真正意义上的模块化。

2. 主流模块化规范发展

2.1 CommonJS

CommonJS是服务器端模块化的规范,由NodeJS推广使用。

每个文件都是一个Module实例,通过module关键字暴露内容

文件内通过require对象来引入指定模块

所有文件加载均是同步完成

模块加载一次之后就会被缓存

模块编译本质上是沙箱编译

只能在服务器端环境上运行

使用CommonJS,上面的例子可这样改写

//name.js

module.exports = {
    name: 'lucy'
};
           

//info.js

var name = require('./name.js');
module.exports = {
    word: 'hello' + name,
    age: 12
};
           

//word.js

var info = require('./info.js');
exports.word = info.word + 'hello word';
           

CommonJS 只需引入一个入口文件(此处为index.js文件),无需再单独引入各依赖文件

//index.js

var info = require('./info.js');
var word = require('./word.js');
console.log('word:', word);
console.log('age:', info.age);
           

CommonJS基于Node原生api在服务端实现模块同步加载,但仅局限于服务端,客户端同步加载依赖时间消耗非常大,那么AMD规范诞生了。

2.2 AMD规范(Asynchronous Module Definition)

异步加载模块,模块的加载不影响它后面语句的运行,所有依赖这个模块的语句,都定义在一个回调函数中,依赖加载完后,这个回调函数才会执行。

AMD规范实际上是 RequireJS 在推广过程中产生的。

AMD规范语法:

//模块定义
define(id?(可选), dependencies?(可选), factory);
//模块引用
require([module], callback);
           

上面例子可简单修改为:

//name.js

define(function(){
	return{
        name: 'lucy'
	}
});
           

//info.js

define(
    ['name'],
    function(name) {
	   return {
		    word: 'hello' + name,
            age: 12
	    }
    };
});
           

//word.js

define(
    "word",
    ['info'],
    function(info) {
	   return info.word + 'hello word'
    };
});
           
require(['info', 'word'], function (){
    console.log('word:', word);
    console.log('age:', info.age);
});
           

对于没有按照AMD规范定义的模块,可在 require() 加载之前,先使用 require.config() 方法定义他们的特征。

2.3 CMD规范

受CommonJS的启发,阿里诞生了一个CMD规范。

AMD 是依赖关系前置,而CMD是按需加载.

语法:

//模块定义
define(function(require, exports, module) {
  // 模块代码
    var a = require('./a')
});
//模块引用
require()
           

AMD 是 RequireJS 在推广过程中对模块定义的规范化产出,CMD 是 SeaJS 在推广过程中对模块定义的规范化产出。

AMD:提前执行(异步加载:依赖先执行)+延迟执行,CMD:延迟执行(运行到需加载,根据顺序执行)

CMD 推崇依赖就近,AMD 推崇依赖前置

// CMD
define(function(require, exports, module) {
var a = require('./a')
a.doSomething()
// ....
var b = require('./b') // 依赖可以就近书写
b.doSomething()
// ... 
})

// AMD 默认推荐的是
define(['./a', './b'], function(a, b) { // 依赖必须一开始就写好
a.doSomething()
// ....
b.doSomething()
...
}) 
           

但后来seaJS逐渐不再维护,CMD规范渐渐淡出视野。

2.4 ES6 模块化

2015年,ES6推出了官方的模块化解决方案。

在 ES6 中,使用export关键字来导出模块,使用import关键字引用模块,export default,为模块指定默认输出,对应导入模块import时,不需要使用大括号

使用import导入模块时,需要知道要加载的变量名或函数名

import 先于模块内的其他模块执行,无法在运行时加载模块,import 和 export 不能在代码块之中

CommonJS 和 ES6 的区别

CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用,原始值改变,import加载的值也会改变。

CommonJS 模块是运行时加载,ES6 模块是编译时输出接口

上面例子用ES6模块化实现如下:

//name.js

export default {
   name: 'lucy' 
}
           

//info.js

import {name} from './name';
export default {
    word: 'hello' + name,
    age: 12
}
           

//word.js

import {name} from './name';
export const word = 'hello' + name;
           
import info from './info';
import {word} from './word';
console.log('word:', word);
console.log('age:', info.age);
           

参考:

https://segmentfault.com/a/1190000000733959?utm_source=sf-related

https://segmentfault.com/a/1190000015302578

https://segmentfault.com/a/1190000010913832#articleHeader4

继续阅读