今天蹲腿,晚上吃氮泵了,睡不着补一篇
模块化的规范
模块化定义: 模块化是指解决一个复杂问题时自顶向下逐层把系统划分成若干模块的过程,有多种属性,分别反映其内部特性。
下面随便说说前端模块化
CommonJS
2009年Nodejs发布,采用 CommonJS 模块规范。
基于Node原生api在服务端可以实现模块同步加载,但是仅仅局限于服务端,客户端如果同步加载依赖的话时间消耗非常大,所以需要一个在客户端上基于Commonjs但是对于加载模块做改进的方案,于是AMD规范诞生了。
AMD/RequireJS
AMD是 (Asynchronous Module Definition)
的缩写,意思就是”异步模块定义”。它采用异步方式加载模块,模块的加载不影响它后面语句的运行。所有依赖这个模块的语句,都定义在一个回调函数中,等到所有依赖加载完成之后(依赖前置),这个回调函数才会运行。
RequireJS
是一个工具库,主要用于客户端的模块管理。它的模块管理遵守AMD规范,RequireJS
的基本思想是,通过 define
方法将代码定义为模块,通过require方法实现代码的模块加载。
特点:浏览器直接运行无需编译,异步加载,依赖关系清晰
CMD/SeaJS
CMD规范专门用于浏览器端,同样是受到Commonjs的启发,国内(阿里)诞生了一个CMD (Common Module Definition)
规范。该规范借鉴了Commonjs的规范与AMD规范,在两者基础上做了改进。
与AMD相比非常类似,CMD规范(2011)具有以下特点:
- define定义模块,require加载模块,exports暴露变量。
- 不同于AMD的依赖前置,CMD推崇依赖就近(需要的时候再加载)
- 推崇api功能单一,一个模块干一件事。
// module.1
define(function (require, exports, module) {
module.exports = {
msg: 'I am module1'
}
})
// module.2
define(function (require, exports, module) {
var module2 = require('./module1')
function show() {
console.log('同步引入依赖模块1 ' + module2.msg)
}
exports.showModule = show
})
// main.js
define(function (require) {
var m2 = require('./modules/module2')
m2.showModule();
})
// html中引入工具库,并定义js主文件
<script type="text/javascript" src="./libs/sea.js"></script>
<script type="text/javascript">
seajs.use('./main')
</script>
UMD
虽然CommonJS和AMD的风格同样大受欢迎,但是看起来似乎它们并没有达成共识。这样的局面也导致了一种能同时支持两种风格的需要出现,这带给了我们通用模块定义。
所谓UMD (Universal Module Definition)
,就是一种javascript通用模块定义规范,让你的模块能在javascript所有运行环境中发挥作用。
ES6
2015年,ES6规范中,终于将模块化纳入JavaScript标准,从此js模块化被ECMA官方扶正,也是后来js的标准。
ES6中的模块化在CommonJS的基础上有所不同,关键字有import,export,default,as,from。
// 模块js
let _moduleName = 'module';
function setModuleName(name) {
_moduleName = name;
}
function getModuleName() {
return _moduleName;
}
export { setModuleName, getModuleName }
// 调用js
import { getModuleName,setModuleName } from './es6.module';
setModuleName("es6 Module");
console.log(getModuleName());
CommonJS和ES6区别:
CommonJS 模块输出的是一个值的拷贝,即原来模块中的值改变不会影响已经加载的该值。/ ES6 模块输出的是值的只读引用,模块内值改变,引用也改变。
CommonJS 模块是运行时加载,加载的是整个模块,即将所有的接口全部加载进来。 /
ES6 模块是编译时输出接口,可以单独加载其中的某个接口。