将一组模块(及其依赖项)以正确的顺序拼接到一个文件(或一组文件)中的过程。javascript
模块是实现特定功能的一组属性和方法的封装。html
将模块写成一个对象,全部的模块成员都放到这个对象里面。java
var module1 = new Object({ _count:0, f1:function(){}, f2:function(){} }) module1.f1() module1.f2()
上面的对象能够改变里面的属性和方法,不安全git
var module1 = (function(){ var count=0; return { f1:function(){}, f2:function(){}} }()); module1.f1() module1.f2() module1.count //undefined
使用 将相应的方法和属性封装在函数中,这样就不会暴露私有成员es6
function Father (){ var arr =[]; this.add = function (val){ arr.push(val) } this.toString = function(){ return arr.join(''); } } var a = new Father(); a.add(1);//[1] a.toString();//"1" a.arr // undefined
上面的函数将 arr
变成私有变量,在函数外部没法访问,可是造成了闭包,很是耗费内存;
违背了构造函数与实例对象在数据上相分离的原则(即实例对象的数据,不该该保存在实例对象之外)。github
function ToString() { this._buffer = []; } ToString.prototype = { constructor: ToString, add: function (str) { this._buffer.push(str); }, toString: function () { return this._buffer.join(''); } };
虽然上面的构造函数未生成闭包,可是外部能够修改方法和属性,不安全数组
若是一个模块很大或者一个模块须要继承另外一个模块能够利用当即执行函数的特效来封装浏览器
var module1 = (function(m1){ mod1.col=function(){ console.log(this) }; return mod1; }(window.modlue2 ||{})) //有些模块多是null 确保函数正常执行 采用兼容模式 window.modlue2 ||{}
var module1 = (function ($, Swiper) { //... }(jQuery, Swiper));
上面的 module1 引入 jQuery 和 Swiper 当作两个参数传入模块中,保证了模块的独立性,还使得模块之间的依赖关系变得明显。缓存
当即执行函数还能够起到命名空间的做用。安全
(function($, window, document) { function go(num) { } function handleEvents() { } function initialize() { } function dieCarouselDie() { } //attach to the global scope window.finalCarousel = { init : initialize, destroy : dieCarouselDie } }( jQuery, window, document ));
以上都有一个共同点:使用单个全局变量箭头代码包装在函数中,使用闭包创建私有空间
可是都有缺点:
CommonJS
是一种思想, 本质上是可复用的JavaScript,它导出特定的对象,提供其它程序使用。
因为 JavaScript
没有模块系统、标准库较少、缺少包管理工具,所以CommonJS
是为它的表现来制定规范。
每一个JavaScript 文件 都将模块存储在本身独有的做用域中。
须要使用 module.exports
和 exports.obj
来导出对象,并在须要它的程序中使用 require('module')
加载
//文件1 function myModule() { this.hello = function() { return 'hello!'; } this.goodbye = function() { return 'goodbye!'; } } module.exports = myModule; //文件2 var myModule = require('myModule'); var myModuleInstance = new myModule(); myModuleInstance.hello(); // 'hello!' myModuleInstance.goodbye(); // 'goodbye!'
var module1 = { export1:{} }; (function (module,exports){ exports.add = functon(val){ return val *10 } }(module1,module1.export1)); var fn = module1.export1.add; fn(2)//20
利用当即执行函数 接受两个参数 module 和 exports, 模块就经过当即执行函数赋值,而后导出模块,便可实现模块的加载
这种方法的好处:
CommonJS
采用服务器优先方法而且同步加载模块,所以在浏览器中使用它会阻止浏览器运行其余内容,直到加载完成。咱们可使用 AMD
来异步加载
define
,经过 define
方法定义模块。define(['myModule', 'myOtherModule'], function(myModule, myOtherModule) { console.log(myModule.hello()); });
上面的 define
函数将每一个模块的依赖项,以数组的形式做为参数。
这些依赖项会在后台异步加载,一旦加载完成,
define
函数就调用模块给出的回调函数
myModule
可能像下面同样定义:
define([], function() { return { hello: function() { console.log('hello'); }, goodbye: function() { console.log('goodbye'); } }; });
CMD
由玉伯大佬提出并用于SeaJSCMD和AMD 不一样点:
define(function(require, exports, module) { var near = require('./a') near.doSomething() // 此处略去 100 行 var nearOne = require('./b') // 依赖能够就近书写 nearOne.doSomething() // ... })
define(['./a', './b'], function(nearTow, nearThree) { // 必须一开始加载 nearTow.doSomething() // 此处略去 100 行 nearThree.doSomething() ... })
CMD
里,没有全局 require,而是根据模块系统的完备性,提供 seajs.use 来实现模块系统的加载启动。CMD 里,每一个 API 都简单纯粹。 AMD
的 API 默认是一个当多个用,CMD 的 API 严格区分,推崇职责单一。好比 AMD 里,require 分全局 require 和局部 require,都叫 require。AMD
和 CommonJS
不一样点:AMD
:
CommonJS
:
UMD
同时支持
AMD
和CommonJS
本质 建立了一种方法来使用二者的任何一种,同时支持全局变量定义,(JS兼容性的经常使用思想)因此UMD
能够在客户端和服务器上工做
(function (root, factory) { if (typeof define === 'function' && define.amd) { // AMD define(['myModule', 'myOtherModule'], factory); } else if (typeof exports === 'object') { // CommonJS module.exports = factory(require('myModule'), require('myOtherModule')); } else { root.returnExports = factory(root.myModule, root.myOtherModule); } }(this, function (myModule, myOtherModule) { function notHelloOrGoodbye(){}; function hello(){}; function goodbye(){}; return { hello: hello, goodbye: goodbye } }));
import
关键字引入模块,经过 export
关键字导出模块//a.js export let cun =1; export function add() { cun++; } //---------------- import { cun, add } from './a.js'; console.log(cun); // 1 incCounter(); console.log(cun); // 2 export var fo ='a'; setTimeout(() => fo ='b',500); import {fo} from './a.js'; console.log(fo);//'a' setTimeout(()=> console.log(fo),500)//'b' //ES6 输入的模块变量,只是一个“符号链接”,因此这个变量是只读的,对它进行从新赋值会报错。 fo = 's' //error
CommonJS
、AMD
和CMD
相比:ES6
模块是动态引用,而且不会缓存值,模块里面的变量绑定其所在的模块。// lib/counter.js var counter = 1; function increment() { counter++; } function decrement() { counter--; } module.exports = { counter: counter, increment: increment, decrement: decrement }; // src/main.js var counter = require('../../lib/counter'); counter.increment(); console.log(counter.counter); // 1