简析-commonJS&AMD&CMD
大概说下三者区别:
CommonJS ---> AMD ---> CMDjavascript
都是使用字符串命名方式,让模块做用域只存在于当前模块做用域内,解决了命名空间的问题,且遵循一个模块表明一个文件的理念,将一个js系统地“分割“成多个模块,实现模块化系统。前端
AMD和CMD都是向着CommonJS致敬的,都有CommonJS的身影。java
CommonJS起初为了解决,服务端的代码,把代码全都挤在一个文件内,从而致使文件复杂臃肿的,浏览器加载该JS文件,产生卡死;全局做用域污染等问题,而应运而生的模块化开发理念。并且其加载模块的方式属于同步的,须要遵循“先加载,停顿,再执行“的顺序来执行代码,所以很受网速限制。node
AMD规范,虽然延续了CommonJS的理念,模块化开发,但不一样的是,AMD遵循的是异步加载模块的规范。其加载依赖模块方式是属于依赖前置,即先加载须要的依赖模块,再执行回调函数,大大提升了效率。python
CMD规范,是由国内前端大神,玉伯,编写的一个js库 --- sea.js,在推过过程,提出的一个基于CommonJS的新规范---CMD。该规范与AMD相似,写法也相似。但不一样的是,CMD遵循着依赖后置的理念。即AMD是一次性加载完该模块所须要的全部模块,再执行回调。而CMD是按需加载,即须要用到的时候,才去加载对应模块。git
虽然说AMD和CMD表明分别是requireJS和seaJS,但要清楚一点,前面2个是规范,后面2个是库,只是模块加载器。github
1. CommonJS
介绍 : CommonJS,期初名字是叫SeverJS,后改成CommonJS。其定义了服务器端模块的规范,记住,只是规范,由Node推广使用(适用于服务端)。api
CommonJS 经过定义一些常见应用程序的API的方式,为模块化开发 JS 提供了一个标准库(后来逐渐造成了规范),用来兼容不一样JS解释器和宿主环境。数组
其目标是提供一个标准库,这个库类比于python,java...浏览器
主要做用是为一些特定对象,定义一些API,提供module.exports来导出模块,require来导入模块。
NodeJS
因为初期js的局限性,项目累计起来,就会全部代码写进一个文件内,容易致使文件过大,加载过久,浏览器容易卡死,关键之前网速和如今千差万别;
不只如此,还会致使做用域污染的问题(全局污染),造成命名空间。并且也不方便与其它项目的系统进行进行交互(这里主要指基于浏览器的应用)。
所以,模块化开发成了必然趋势,因而便有了Common Js。
然而在2009年,一位美国佬建立了一个语言上基于js,规范遵循着时下流行且实用的CommonJS规范的Node JS,更是将CommonJS推向了高潮,得益于node Js的火热。
1. module.exports ------ 用于导出当前模块。
2. require ------ 这个require和AMD的require不一样。
复制代码
模块化,遵循一个模块一个文件的原则。
耦合低,不容易致使全局变量的污染,由于每一个模块都至关于闭包,都存在于本身的命名空间模块内的做用域。所以,外部没法访问内部私有变量,。
单一原则。每一个模块内部都包含一个自执行函数,而这里提供2个变量,一个exports,一个module,可是最后输出的值,是在module.exports。
统一性,都使用module.exorts或exports来导出模块,而后使用require()函数来导入模块(同步)。
高度复用,能够将别人的项目内某个功能之间导入使用。(前提是用module.exports或exports导出)。
不兼容浏览器,不能直接使用。由于浏览器不支持global,module,require,exports这四个全局变量。
由于期初CommonJS的出现是应用在服务端,并且它的加载方式属于同步的,注意,是加载时是同步的。所以,编码时必须先去加载模块,再执行,这样会影响后面的代码的执行时间,造成阻塞。
2. AMD
因为出现了CommonJS规范,并且因为NodeJS的推广的缘由,使得JS在服务端大放光彩,能干不少其余语言能干的事(java,python等)。
可是(AMD出现的缘由),这只是服务端的,毕竟客户端仍是不能直接支持CommonJS规范的(至于为何不支持查看CommonJS介绍)。而JS宿主就是以浏览器为大头的,哪能不行呢?
因此,时代造英雄,AMD英雄降临了。
AMD的出现主要解决客户端的模块化开发问题,并且 AMD又延续CommonJS规范的精神,都是模块化开发,都是将模块做用域定义在命名空间内,防止了全局变量的污染。
但同时也很大不同。
AMD:“由于我是异步加载模块的!!!“
require.JS
AMD 定义了一套 JS 模块依赖的异步加载标准,来解决同步加载的问题。
// 其实有不少方法,但该方法也是官网推荐用法:
// 匿名定义模块:
define([依赖1,依赖2...],()=> {
// 依赖加载完后,执行回调函数...
})
复制代码
// 这点和commonJS的require有点不同,AMD须要2个参数,且有回调。
const 变量 = require([模块名],function() {
// 执行回调操做...
})
复制代码
模块化,遵循CommonJS理念,一个文件即模块。
低耦合,因为采用命名空间内做用域有效,全部外部没法访问私有变量。
统一性,都由全局变量define函数(导出)定义模块,全局变量require函数导入模块。
高效性,因为采用的是异步加载的方式来加载模块,加载方法和CommonJS “同样“,都是使用require来加载模块。可是AMD的require有点不同,AMD的require导入模块时是异步的,并且语法是:require([依赖1,依赖2...],function() {})。也就是说,要先加载完全部依赖,才执行回调函数,而该回调回调函数的参数,也必须严格按照数组内的模块顺序来做为参数,回调函数内都是依赖于这些模块的逻辑代码。那些和这些依赖无关的,能够写在外面,在加载依赖时,是不会影响接下来的代码的。这也就对应了:异步加载,是不会影响后面的代码的运行的。
关系前置,我我的称为 “依赖前置“ 。可能因为设计思想的缘由,AMD虽然说是异步加载模块,但倒是一次性加载完了对应模块,再执行回调。虽然说没毛病,我只有等我须要的装备都齐了,才能打boss,这也说的过去。可是从人性化来看,就不怎么好了,我但愿我想加载哪一个的时候,再加载,不想加载的时候,你就别动。这点能够查看下面CMD的优势。
写法比较轻浮,光是定义模块就有好几种写法(虽然说官网有推荐写法---定义模块)。但这对初学者的我,会产生不少疑惑,也浪费了不少比较的时间。
3. CMD
CMD,即Common Module Definition,通用模块定义。
因为AMD的出现,模块化开发再也不是服务端独有的了,浏览器也能实现模块化开发了。但带来便捷的同时,天然也有须要诟病的地方。 好比前面说的,因为设计理念上,AMD是遵循 关系前置,也就是依赖前置的规范,来加载模块。这就致使了一个问题,不够人性化,体现不了按需加载的feel~
所以,国内牛人就AMD基础上,出了个seaJS,同时在推广过程,衍生出一种新的规范---CMD。 从字面意思就能大概猜出,CMD是比较贪心的啊,想作通用的规范哦。 但从语法上看,却不是。 seaJS,其职责单一,严格遵循一个模块就是一个文件的理念,是更接近CommonJS的理念的(具体哪一个理念本身查)。
上面说到就AMD基础上出的seaJS,那就是有相同之处了,这里只说不一样之处。
CMD 特别就在于,体现了按需加载的理念。 能作到用同步的写法,实现出按需加载的效果。 具体看下面API介绍。
// 1. require:
// 在定义时能够去加载须要的依赖:
define(function(require,exports,module) {
// 按需加载模块:
let a = require(./b)
})
// 2. exports
// exports 是一个对象,用来向外提供模块接口:
define(function(require,exports,module) {
// 按需加载模块:
let a = require(./b)
let a_obj = {
a: a
}
// 导出方法:
// 方法01:
exports.a = a;
// 或者导出一个function也是能够的.
// 方法02:
// 使用return来直接代替exports
return {
a: a
}
// 这里实例一个错误的写法,归纳为:不能直接给exports赋值,由于最后导出的是module.exports,这样是不会改变模块的值的:
// 错误:
exports = {
a: a
}
// 正确:
module.exports = {
a: a
}
// 3. module:
module.exports必须是同步执行,不能放在回调里执行:
// 好比定时器:
// 错误用法
setTimeout(function() {
module.exports = { a: "hello" };
}, 0);
})
复制代码