本文可能不涉及一些基础概念,好比什么是模块,对每种方案也没有都作详细的解释(若是解释的话,每一个都值得一篇文章),准备和落实这篇文章主要是有两方面缘由。javascript
CommonJS
,seaJS
,CMD
,AMD
,UMD
,Browserify
,RequireJS
,知道他们和js模块有关,但具体是什么关系,js模块化应该用哪一个的倒是不知道。综上两点,就是对JS的模块不熟悉致使的。前端
对JS模块化有一个直面的了解,并能捋清楚各个规范之间的之间的联系,再遇到这些名词不会再有它认识我,我不认识它
的感受java
首先来讲为何须要模块化,这个你们内心应该都有一两个答案,好比避免命名冲突啊,全局变量过多啊,依赖很差管理啊等等等等。总得来讲模块化大方向上有几个好处。node
整体上模块化基本上是一个百利无一害的实现jquery
开始JS没有模块的概念,所以致使了不少问题,好比命名冲突,好比:webpack
var origin = 100;
....其余代码
var origin = 1232;
....其余代码
console.log(origin)//目标是让它输出100,但实际会输出1232,由于后来的命名覆盖
复制代码
还有依赖问题,好比a.js依赖了b.js,那么下载时必须是先下载b,在下载a,顺序必定不能错。web
为了解决这些没有模块带来的问题,前辈们提出了使用IIFE来模仿模块,以下:gulp
(function(){
var name = 'wingtao;
var sayHello = function (){
console.log('hello '+name);
}
sayHello(); // hello wingtao
})()
复制代码
上面利用当即执行函数模拟了一个模块,该模块中的变量外界没法访问,避免了命名冲突的问题,jQuery就用了这种方式,api
(function(global){
global.jquery = ...
})(window);
复制代码
但仍是没有彻底实现模块化,如对模块依赖的管理、如何将api暴露出来而不污染全局环境浏览器
CommonJS社区首先提出了模块化的规范CommonJS,因此CommonJS是一个规范!在node上只须要简单的require和exports就能够实现模块的导入和导出,以下:
a.js
exports.add = function(a,b){
return a+b;
}
b.js
var add = require('a.js').add;
console.log(add(1,2))//3
复制代码
看起来很是棒!并且nodeJS模块实现了这种规范,意味着在node中能够直接使用这种方式。
既然服务端能实现了这种模块化的规范,浏览器上对此也是很是迫切的,天然也是想要实现这块,可是直接拿来用是有一些问题,
所以若是想在浏览器上使用CommonJS是须要改造的,对此人们分红了几派,一派是认为仍是按照CommonJS规范来,只是加上函数包裹和异步加载,在浏览器上能执行就好了;一派认为CommonJS不适合浏览器端,须要一个新的规范;第三方是个“和稀泥”的,认为CommonJS和从新改革都有可取之处,因此各取所长。
其中第一派坚持使用CommonJS的作出了浏览器端的实现Browserify,名字也很形象,Browserify能够将node端模块文件转换为浏览器可识别的模块文件。因此Browserify是CommonJS在浏览器端的实现
AMD(规范)其实就是上面说的第二派,就是抛弃CommonJS,提出新的可异步加载的模块规范。AMD最大的特色即是能够异步加载模块,它的实现是RequireJS,编写时像这样:
define(['myModule', 'myOtherModule'],function(myModule, myOtherModule) {
console.log(myModule.hello());
});
复制代码
过程是先加载依赖myModule,myOtherModule(后台不阻塞的方式加载),加载完成后执行回调函数,其中回调函数的参数即是已经加载完成的模块。其实AMD仍是有不少问题的,好比define的时候全部依赖要挨个写一遍,好比无论如今用不用的到都会把依赖先下载下来,不过这些问题AMD都有优化,这里不提。
UMD全称是Universal Module Definition,目的兼容CommonJS和AMD,因此它会作一层判断,判断当前环境是浏览器仍是node,若是是浏览器则使用AMD,node环境使用CommonJS方式,UMD实现了两种环境的兼容,但同时也致使了十分臃肿,肉眼观察实在有点费劲。
提起CMD,不怕被笑话,我以前还觉得和CommonJS是同一个东东呢😂。seaJS是阿里前端工程师玉伯作出来的,并提出了CMD,CMD吸收了AMD和CommonJS二者的优势,融合了百家之长(但好像只在国内有影响,国外影响有限),因此CMD是规范而seajs是它的实现。
以上说的种种方式都是由于ECMA缺少官方的模块规范才出来的,既然对模块化的需求这么旺盛,官方在ES2015(ES6)里也就提出了官方的模块化方案,主要使用import和export,用法很是简单,并且它和以前的方案的区别除了它是官方提出而且写法简单以外,还有重要的一点就是它是静态解析的,什么是静态解析呢?另开一篇文章再讲,不过这个特性能够带来不少优化,如tree-shaking。ES6模块机制理论上是浏览器原生支持的,但实际上如今支持度还不够,这个你们应该也能理解,不过在将来应该可能就能在浏览器中直接加载导出模块了,
这些工具其实和上面讲的模块规范已经不是一个维度的事情了,上面说的是模块化,这些是一些能够打包的工具,打包什么呢?模块!这就是他们之间的联系了。就不展开讲了,这是三个东西太多了。
简单总结一下上面讲的东西,其实就是讲了下js模块的几个方案,每一个方案都有本身的规范,然而只有规范还不行,须要有实现来支持它,因此总得来讲就是:
环境 | 规范 | 实现 |
---|---|---|
node | CommonJS | nodejs 模块 |
浏览器 | CommonJS | Browserify |
浏览器 | AMD | RequireJS |
浏览器 | UMD | 👆二者 |
浏览器 | CMD | SeaJS |
写下来这些就是但愿本身能对js模块化有一个较为全面的了解,面对这些名词再也不默认,并了解他们之间的关系。
文章仓促,有不足之处但愿多多指出。
若是你看完对你有些许的帮助,那是意外之喜😊。