先列举下一些著名言论:

“我想定义一个 each 方法遍历对象,但页头的 util.js 里已经定义了一个,我的只能叫 eachObject 了,好无奈。”

“RequireJS 是没有明显的 bug,SeaJS 是明显没有 bug。”

“在用SeaJS,除了打包非常痛苦外,其他的还好”

“你变了精彩的魔术,我们会为你喝彩。但你想让我们信任你,你得主动解释魔术的奥秘。否则我会觉得自己被耍了。”

“这两个加载器和标准没有优劣之分,只有差别。具体还是要根据实际情况进行选择;”

……

前端模块化

这个是个老掉牙的话题,我就不再误人子弟了,欢迎阅读这篇由 玉伯 大大执笔的《 前端模块化开发的价值

模块化能解决:

  • 模块的版本管理 。通过别名等配置,配合构建工具,可以比较轻松地实现模块的版本管理。

  • 提高可维护性 。模块化可以让每个文件的职责单一,非常有利于代码的维护。Sea.js 还提供了 nocache、debug 等插件,拥有在线调试等功能,能比较明显地提升效率。

  • 前端性能优化 。Sea.js 通过异步加载模块,这对页面性能非常有益。Sea.js 还提供了 combo、flush 等插件,配合服务端,可以很好地对页面性能进行调优。

  • 跨环境共享模块 。CMD 模块定义规范与 Node.js 的模块规范非常相近。通过 Sea.js 的 Node.js 版本,可以很方便实现模块的跨服务器和浏览器共享。

sea.js 举例

sea.js是一个专门为解决浏览器模块化开发的方案,SeaJS定义了一个全局函数 define 它用来定义一个模块,SeaJS提倡:文件即模块。

  • 先贴一段模块代码

所有模块都通过 define 来定义

define(function(require, exports, module) {

	// 通过 require 引入依赖 注意 .js 可以省略
var $ = require('jquery');
// 你也可以引入自己的函数依赖
var Spinning = require('./yourFunction');
var util = {};
util.sayHello = function(){
return 'seajs向你问好';
}
// 通过 exports 对外提供接口
// exports 和 module.exports 区别见下文:
//exports.doSomething = function() { //};
// 或者通过 module.exports 提供整个接口
module.exports = util; });
// 看完这一段 你应该明白了 require, exports, module 三个参数

前端模块化开发的历史

既然是 回顾 那就应该好文不断: 《 前端模块化开发那点历史

AMD规范及其代表: RequireJS

AMD规范

  • 中文版在这里AMD (中文版),或者: 鸟语原版

  • 简单说: 就是 异步模块定义(Asynchronous Module Definition),它是 依赖前置 (因为依赖必须一开始就写好)会先 尽早地执行(依赖)模块 , 相当于所有的require都被提前了,它的 require 分全局和局部, 一个API当多个用

  • define() 函数

看下它的具体参数说明

define(
//这个模块的名称
"types/Manager",
//依赖的模块
["types/Employee"],
//函数执行时,所有依赖项加载。这个函数的参数依赖上述模块。
function (Employee) {
function Manager () {
this.reports = [];
}
//开始执行
Manager.prototype = new Employee();
//返回经理构造函数可以由其他模块的应用。
return Manager;
}
);

一些例子

创建一个名为"alpha"的模块,使用了require,exports,和名为"beta"的模块:

define("alpha", ["require", "exports", "beta"], function (require, exports, beta) {
exports.verb = function() {
return beta.verb();
//或者:
//return require("beta").verb();
}
});

一个返回对象的匿名模块:

define(["alpha"], function (alpha) {
return {
verb: function(){
return alpha.verb() + 2;
}
};
});

一个使用了简单CommonJS转换的模块定义:

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

CMD规范及其代表: SeaJS

CMD规范

  • 中文版在这里CMD 模块定义规范 ,也有 鸟语版

  • 简单说 : CMD(Common Module Definition)更贴近 CommonJS Modules/1.1 和 Node Modules 规范,一个模块就是一个文件;它推崇 依赖就近 想什么时候 require 就什么时候加载,实现了 懒加载, 延迟执行 (as lazy as possible) ;也没有全局 require, 每个API都简单纯粹

  • define() 函数类似,看定义即可

module.exports 和 exports 区别

经常使用的 API 只有 define, require, require.async, exports, module.exports 这五个。其他 API 有个印象就好。

传给 factory 构造方法的 exports 参数是 module.exports 对象的一个引用。只通过 exports 参数来提供接口,有时无法满足开发者的所有需求。 比如当模块的接口是某个类的实例时,需要通过 module.exports 来实现:

define(function(require, exports, module) {
// exports 是 module.exports 的一个引用
console.log(module.exports === exports); // true
// 重新给 module.exports 赋值
module.exports = new SomeClass();
// exports 不再等于 module.exports
console.log(module.exports === exports); // false
});

对 module.exports 的赋值需要同步执行,不能放在回调函数里。下面这样是不行的:

// x.js
define(function(require, exports, module) {
// 错误用法
setTimeout(function() {
module.exports = { a: "hello" };
}, 0); });

在 y.js 里有调用到上面的 x.js:

// y.js
define(function(require, exports, module) { var x = require('./x'); // 无法立刻得到模块 x 的属性 a
console.log(x.a); // undefined });

AMD(RequireJS)和CMD(SeaJS)异同

看看执行流程

当我们看到RequireJS 的接口,

require(['a','b'],function(){
//Do something
})

实际做的事情是:

1、require 函数检查依赖的模块,根据配置文件,获取js文件的实际路径

2、根据js文件实际路径,在dom中插入script节点,并绑定onload事件来获取该模块加载完成的通知。

3、依赖script全部加载完成后,调用回调函数

Sea.js在调用时

define('a',function(require,exports,modules){
var b = require('b')
})

1、通过回调函数的Function.toString函数,使用正则表达式来捕捉内部的require字段,找到require('jquery')内部依赖的模块jquery

2、根据配置文件,找到jquery的js文件的实际路径

3、在dom中插入script标签,载入模块指定的js,绑定加载完成的事件,使得加载完成后将js文件绑定到require模块指定的id(这里就是jquery这个字符串)上

4、回调函数内部依赖的js全部加载(暂不调用)完后,调用回调函数

5、当回调函数调用require('jquery'),即执行绑定在'jquery'这个id上的js文件,即刻执行,并将返回值传给var b

注意: SeaJS 这种用 ** 正则表达式 捕捉require内部依赖模块的方式** ,使得无法利用尚未执行的回调函数中的js运行环境,导致require函数的内部只能将依赖的模块名称硬编码,就不能写下面这样的代码了

define('a',function(require,exports,modules){
//错误
var b = require('Us'+'er');
})

而只能写成

define('a',function(require,exports,modules){
//正确
var b = require('User');
})

其他的区别其实介绍时已经说明了,上文~ 小总结:玉伯:与 RequireJS 的异同

相同之处

RequireJS 和 Sea.js 都是模块加载器,倡导模块化开发理念,核心价值是让 JavaScript 的模块化开发变得简单自然。

不同之处

两者的主要区别如下:

  • 定位有差异。RequireJS 想成为浏览器端的模块加载器,同时也想成为 Rhino / Node 等环境的模块加载器。Sea.js 则专注于 Web 浏览器端,同时通过 Node 扩展的方式可以很方便跑在 Node 环境中。

  • 遵循的规范不同。RequireJS 遵循 AMD(异步模块定义)规范,Sea.js 遵循 CMD (通用模块定义)规范。规范的不同,导致了两者 API 不同。Sea.js 更贴近 CommonJS Modules/1.1 和 Node Modules 规范。

  • 推广理念有差异。RequireJS 在尝试让第三方类库修改自身来支持 RequireJS,目前只有少数社区采纳。Sea.js 不强推,采用自主封装的方式来“海纳百川”,目前已有较成熟的封装策略。

  • 对开发调试的支持有差异。Sea.js 非常关注代码的开发调试,有 nocache、debug 等用于调试的插件。RequireJS 无这方面的明显支持。

  • 两者代码质量有差异。RequireJS 是没有明显的 bug,SeaJS 是明显没有 bug。

  • 插件机制不同。RequireJS 采取的是在源码中预留接口的形式,插件类型比较单一。Sea.js 采取的是通用事件机制,插件类型更丰富。

还有不少差异,涉及具体使用方式和源码实现,欢迎有兴趣者研究并发表看法。

总之,如果说 RequireJS 是 Prototype 类库的话,则 Sea.js 致力于成为 jQuery 类库。

还不够

这里有一个图文并茂的 “栗子” SeaJS与RequireJS最大的区别,当然楼主的观点更赞成这个“栗子”: LABjs、RequireJS、SeaJS 哪个最好用?为什么?

结论: 这两个加载器和标准没有优劣之分,只有差别。具体还是要根据实际情况进行选择;


回顾:前端模块化和AMD、CMD规范(全)的更多相关文章

  1. JavaScript的模块化之AMD&CMD规范

    前端开发常常会遇到的问题: 1.恼人的命名冲突: 2.繁琐的文件依赖: 模块化开发的优势: 1.解决命名冲突和依赖管理: 2.模块的版本管理: 3.提高代码的可维护性: 4.前端性能优化: JavaS ...

  2. [整理]前端模块化开发AMD CMD

    前端模块化开发的价值 AMD (中文版) CMD 模块定义规范 标准构建 http://seajs.org http://chaoskeh.com/blog/why-seajs.html http:/ ...

  3. 前端模块化和AMD、CMD规范

    前端模块化和AMD.CMD规范 先看下基础:https://github.com/seajs/seajs/issues/547

  4. 前端模块化,AMD与CMD的区别

    最近在研究cmd和amd,在网上看到一篇不错的文章,整理下看看. 在JavaScript发展初期就是为了实现简单的页面交互逻辑,寥寥数语即可:如今CPU.浏览器性能得到了极大的提升,很多页面逻辑迁移到 ...

  5. 前端笔记之ES678&Webpack&Babel(下)AMD|CMD规范&模块&webpack&Promise对象&Generator函数

    一.AMD和CMD规范(了解) 1.1传统的前端开发多个js文件的关系 yuan.js中定义了一个函数 function mianji(r){ return 3.14 * r * r } main.j ...

  6. JavaScript模块化CommonJS/AMD/CMD/UMD/ES6Module的区别

    目录 JS-模块化进程 原始的开发方式 CommonJS && node.js AMD && Require.js CMD && Sea.js UMD ...

  7. JS开发之CommonJs和AMD/CMD规范

    CommonJS是主要为了JS在后端的表现制定的,他是不适合前端的,AMD(异步模块定义)出现了,它就主要为前端JS的表现制定规范. 在兼容CommonJS的系统中,你可以使用JavaScript开发 ...

  8. javascript模块化编程的cmd规范(sea.js)

    CMD(Common Module Definition,通用模块定义)是一种模块定义规范,规范中明确了模块的基本书写格式和基本交互规则.SeaJS就是遵循的这个规范. define函数 在CMD规范 ...

  9. 深度扫盲JavaScript的模块化(AMD , CMD , CommonJs 和 ES6)

    原文地址 https://blog.csdn.net/haochangdi123/article/details/80408874 一.commonJS 1.内存情况 对于基本数据类型,属于复制.即会 ...

随机推荐

  1. CentOS7安装搭建.Net Core 2.0环境-详细步骤

    一.构建.Net core 2的应用程web发布 因为是用来测试centos上的core 环境,先直接用vs17自带的core实例. 二.部署CentOS7的core环境 1.连接并启动之前安装的虚拟 ...

  2. Windows Server 2008 R2终端服务器激活方法

    本文描述了如何激活Windows Server 2008 R2的终端服务器的方法. 目录: 1.Windows Server  2008 R2终端服务器的安装 2.Windows Server  20 ...

  3. linux之在当前目录下按照文件大小进行排序的三种方法

    当前目录下按照文件大小排序 [root@test23 script]# ls -lSh 总用量 44K -rw-r--r-- 1 root root 2.4K 12月 8 17:24 test.con ...

  4. Linux 内存使用率

    文章参考: 1.正确计算linux系统内存使用率 2.Linux系统内存消失与slab使用之谜 例如当前主机内存信息如下: [zhang@test ~]$ cat /proc/meminfo MemT ...

  5. 【BZOJ3529】数表

    数表 Description 有一张 n*m 的数表,其第i行第j列(1<=i<=n,1<=j<=m)的数值为能同时整除 i和j的所有自然数之和.给定a,计算数表中不大于a的数 ...

  6. Perfect Pth Powers pku-1730(筛+合数分解)

    题意:x可以表示为bp, 求这个p的最大值,比如 25=52, 64=26,  然后输入x 输出 p 就是一个质因子分解.算法.(表示数据上卡了2个小时.) 合数质因子分解模板. ]; ]; ; ;n ...

  7. JDBC驱动-MySQL

    <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</a ...

  8. 转载 【.NET基础】--委托、事件、线程(1) https://www.cnblogs.com/chengzish/p/4559268.html

    [.NET基础]--委托.事件.线程(1)   1,委托 是存放方法的指针的清单,也就是装方法的容器 A, 新建winform项目[01委托],项目中添加dg_SayHi.cs 委托类 用于存储方法 ...

  9. day14 Python函数之可变长参数

    函数参数 1.形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元.因此,形参只在函数内部有效.函数调用结束返回主调用函数后则不能再使用该形参变量 2.实参可以是常量.变量.表 ...

  10. oracle SQL 执行顺序

    Oracle执行SQL查询语句的步骤 1.SQL正文放入共享池(shared pool)的库缓存(library cache). 2.检查是否有相同的SQL正文,没有就进行以下编译处理,否则跳过. 1 ...