JS模块规范:AMD,CMD,CommonJS
浅析JS模块规范
随着JS模块化编程的发展,处理模块之间的依赖关系成为了维护的关键。
AMD,CMD,CommonJS是目前最常用的三种模块化书写规范。
CommonJS
CommonJS规范是诞生比较早的。NodeJS就采用了CommonJS。是这样加载模块:
var modA= require('modA');
modA.start();
这种写法适合服务端,因为在服务器读取模块都是在本地磁盘,加载速度很快。但是如果在客户端,加载模块的时候有可能出现“假死”状况。比如上面的例子中clock的调用必须等待clock.js请求成功,加载完毕。那么,能不能异步加载模块呢?
AMD
AMD,即 (Asynchronous Module Definition),这种规范是异步的加载模块,requireJs应用了这一规范。先定义所有依赖,然后在加载完成后的回调函数中执行:
require([module], callback);
用AMD写上一个模块:
require(['modA'],function(modA){
modA.start();
});
AMD虽然实现了异步加载,但是开始就把所有依赖写出来是不符合书写的逻辑顺序的,能不能像commonJS那样用的时候再require,而且还支持异步加载后再执行呢?
CMD
CMD (Common Module Definition), 是seajs推崇的规范,CMD则是依赖就近,用的时候再require。它写起来是这样的:
define(function(require, exports, module) {
var modA= require('modA');
modA.start();
});
AMD和CMD最大的区别是对依赖模块的执行时机处理不同,而不是加载的时机或者方式不同,二者皆为异步加载模块。
AMD依赖前置,js可以方便知道依赖模块是谁,立即加载;而CMD就近依赖,需要使用把模块变为字符串解析一遍才知道依赖了那些模块,这也是很多人诟病CMD的一点,牺牲性能来带来开发的便利性,实际上解析模块用的时间短到可以忽略。
深入解析JS模块规范
无模块时代
if(xx){
//.......
}
else{
//xxxxxxxxxxx
}
for(var i=; i<; i++){
//........
}
element.onclick = function(){
//.......
}
代码简单的堆在一起,只要能从上往下依次执行就可以了。
模块萌芽时代
<script type="text/javascript" src="a.js"></script>
<script type="text/javascript" src="b.js"></script>
顺序不能错,也不能漏写某个。在多人开发的时候很难协调。
modA = function(){
var a,b; //变量a、b外部不可见
return {
add : function(c){
a + b + c;
},
format: function(){
//......
}
}
}()
这样function内部的变量就对全局隐藏了,达到是封装的目的。但是这样还是有缺陷的,modA这个变量还是暴漏到全局了,随着模块的增多,全局变量还是会越来越多。
app.util.modA = xxx;
app.tools.modA = xxx;
app.tools.modA.format = xxx;
Yahoo的YUI早期就是这么做的,调用的时候不得不这么写:
app.tools.modA.format();
(function(window){
//代码
window.jQuery = window.$ = jQuery;//通过给window添加属性而暴漏到全局
})(window);
模块化面临什么问题
源自nodejs的规范CommonJs
1. 模块的标识应遵循的规则(书写规范)2. 定义全局函数require,通过传入模块标识来引入其他模块,执行的结果即为别的模块暴漏出来的API3. 如果被require函数引入的模块中也包含依赖,那么依次加载这些依赖4. 如果引入模块失败,那么require函数应该报一个异常5. 模块通过变量exports来向往暴漏API,exports只能是一个对象,暴漏的API须作为此对象的属性。
//math.js
exports.add = function() {
var sum = , i = , args = arguments, l = args.length;
while (i < l) {
sum += args[i++];
}
return sum;
};
//increment.js
var add = require('math').add;
exports.increment = function(val) {
return add(val, );
};
//program.js
var inc = require('increment').increment;
var a = ;
inc(a); //
服务端向前端进军
1. 全局有一个module变量,用来定义模块2. 通过module.declare方法来定义一个模块3. module.declare方法只接收一个参数,那就是模块的factory,次factory可以是函数也可以是对象,如果是对象,那么模块输出就是此对象。4. 模块的factory函数传入三个参数:require,exports,module,用来引入其他依赖和导出本模块API5. 如果factory函数最后明确写有return数据(js函数中不写return默认返回undefined),那么return的内容即为模块的输出。
//可以使用exprots来对外暴漏API
module.declare(function(require, exports, module)
{
exports.foo = "bar";
});
//也可以直接return来对外暴漏数据
module.declare(function(require)
{
return { foo: "bar" };
});
AMD/RequireJs的崛起与妥协
1. 用全局函数define来定义模块,用法为:define(id?, dependencies?, factory);2. id为模块标识,遵从CommonJS Module Identifiers规范3. dependencies为依赖的模块数组,在factory中需传入形参与之一一对应4. 如果dependencies的值中有"require"、"exports"或"module",则与commonjs中的实现保持一致5. 如果dependencies省略不写,则默认为["require", "exports", "module"],factory中也会默认传入require,exports,module6. 如果factory为函数,模块对外暴漏API的方法有三种:return任意类型的数据、exports.xxx=xxx、module.exports=xxx7. 如果factory为对象,则该对象即为模块的返回值
//a.js
define(function(){
console.log('a.js执行');
return {
hello: function(){
console.log('hello, a.js');
}
}
});
//b.js
define(function(){
console.log('b.js执行');
return {
hello: function(){
console.log('hello, b.js');
}
}
});
//main.js
require(['a', 'b'], function(a, b){
console.log('main.js执行');
a.hello();
$('#b').click(function(){
b.hello();
});
})
b.js执行
main.js执行
hello, a.js
define(['a', 'b', 'c', 'd', 'e', 'f', 'g'], function(a, b, c, d, e, f, g){ ..... })
define(function(){
console.log('main2.js执行');
require(['a'], function(a){
a.hello();
});
$('#b').click(function(){
require(['b'], function(b){
b.hello();
});
});
});
a.js执行
hello, a.js
var a = require('a');
a.hello();
$('#b').click(function(){
var b = require('b');
b.hello();
});
//d.js
define(function(require, exports, module){
console.log('d.js执行');
return {
helloA: function(){
var a = require('a');
a.hello();
},
run: function(){
$('#b').click(function(){
var b = require('b');
b.hello();
});
}
}
});
require(['d'], function(d){
});
b.js执行
d.js执行
兼容并包的CMD/seajs
//a.js
define(function(require, exports, module){
console.log('a.js执行');
return {
hello: function(){
console.log('hello, a.js');
}
}
});
//b.js
define(function(require, exports, module){
console.log('b.js执行');
return {
hello: function(){
console.log('hello, b.js');
}
}
});
//main.js
define(function(require, exports, module){
console.log('main.js执行'); var a = require('a');
a.hello(); $('#b').click(function(){
var b = require('b');
b.hello();
}); });
a.js执行
hello, a.js
hello, b.js
var b = require.async('b');
b.hello();
以上这些只是为了学习做的总结,有部分摘自大牛原话,本人只是为了学习方便做的笔记,如有侵权,联系必删,致敬大牛!
JS模块规范:AMD,CMD,CommonJS的更多相关文章
- js模块系统 - amd|cmd|commonjs|esm|umd
写过前端代码大概率听说过amd cmd umd commonjs esm这些名词, 想当初我第一次看到这些的时候, 人都麻了, 都是些啥啊. 后来我知道了, 这些都是js的模块规范. amd - 浏览 ...
- JS模块之AMD, CMD, CommonJS、UMD和ES6模块
CommonJS 传送门 同步加载,适合服务器开发,node实现了commonJS.module.exports和require 判断commonJS环境的方式是(参考jquery源码): if ( ...
- 兼容多种模块规范(AMD,CMD,Node)的代码
在JavaScript模块化开发中,为了让同一个模块可以运行在前后端,以及兼容多种模块规范(AMD,CMD,Node),类库开发者需要将类库代码包装在一个闭包内. AMD规范 AMD,即“异步模块定义 ...
- js模块化开发 AMD CMD Commonjs
在es6全面实行开来之前 js实现模块开发方案有: 1.AMD 异步模块开发定义 依赖前置,requireJs应用了这一规范 require([module], callback); 加载完后回调 ...
- 浅析JS模块规范:AMD,CMD,CommonJS
from:https://www.jianshu.com/p/09ffac7a3b2c 随着JS模块化编程的发展,处理模块之间的依赖关系成为了维护的关键. 模块化 AMD,CMD,CommonJS ...
- JavaSript模块规范 - AMD规范与CMD规范介绍(转)
JavaSript模块规范 - AMD规范与CMD规范介绍 JavaSript模块化 在了解AMD,CMD规范前,还是需要先来简单地了解下什么是模块化,模块化开发? 模块化是指在解决某一个复杂问题或者 ...
- JS模块规范 前端模块管理器
一:JS模块规范(为了将js文件像java类一样被import和使用而定义为模块, 组织js文件,实现良好的文件层次结构.调用结构) A:CommonJS就是为JS的表现来制定规范,因为js没有模块的 ...
- FW: AMD, CMD, CommonJS和UMD
javascript 我是豆腐不是渣 4月5日发布 推荐 2 推荐 收藏 32 收藏,486 浏览 今天由于项目中引入的echarts的文件太大,requirejs经常加载超时,不得不分开来加载ech ...
- AMD, CMD, CommonJS和UMD
我的Github(https://github.com/tonyzheng1990/tonyzheng1990.github.io/issues),欢迎star 今天由于项目中引入的echarts的文 ...
随机推荐
- 微信小程序的标签和html标签比较
html 小程序 <div></div> <view></view> <h1><h2>....<h6> <p& ...
- aclocal-1.13: command not found
原因: 将编译好的工程拷贝到系统版本不一样的系统中,再进行编译会出现此类问题. 解决方法: yum install automake autoconf yum install libtool auto ...
- OneDrive for Business
一.界面介绍 1.在Office 365主页 点击“OneDrive”登陆 2.进入OneDrive,可对文档进行存储.同步并共享文档. 3.点击,可对文档进行编辑.分享.重命名等操作 二.文档同步 ...
- [LC] 434. Number of Segments in a String
Count the number of segments in a string, where a segment is defined to be a contiguous sequence of ...
- Grails Controller - redirect 方法
官方文档: http://docs.grails.org/latest/ref/Controllers/redirect.html 网页跳转方法1: // 在一个Action中直接跳转到另外一个Act ...
- FP-Grow树
序言 FP-growth(Frequent Pattern Tree, 频繁模式树),是韩家炜老师提出的挖掘频繁项集的方法,是将数据集存储在一个特定的称作FP树的结构之后发现频繁项集或频繁项对,即常在 ...
- linux系统开机静态分配ip地址
在/etc/sysconfig/network-scripts/ifcfg-eth0文件中 添加: IPADDR=192.168.1.100(设置静态地址) NETMASK=255.255.255.0 ...
- python3下scrapy爬虫(第七卷:编辑器内执行scrapy)
之前我们都是在终端切入到scrapy的路境内执行爬虫的,你要多敲多少行的字节,所以这次我们谈谈如何在编辑器里执行,这个你可以用在爬虫中,当你使用PYTHONWEB开发时尽量不要在编辑器内启动端口服务那 ...
- 羽翼sqlmap视频笔记
access 注入 ./sqlmap.py -u "url" 注入判断./sqlmap.py -u "url" --tables 跑表./s ...
- [LC] 64. Minimum Path Sum
Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right which ...