一,??榛?
-
定义:
所谓的??榛⒕褪欠庾跋附?,提供使用接口,彼此之间互不影响,每个??槎际鞘迪帜骋惶囟ǖ墓δ堋D?榛⒌幕【褪呛?/p>
-
使用函数封装:
function func1(){ //... } function func2(){ //... }
注释 :
上面的函数func1 ()和func2 (),组成一个???。使用的时候,直接调用就行了。这种做法的缺点很明显:影响了全局变量,无法保证不与其他??榉⑸淞棵逋?,而且??槌稍敝淇床怀鲋苯庸叵怠?/p>
-
立即执行函数的写法:
使用"立即执行函数"(Immediately-Invoked FunctionExpression,IIFE),可以达到不暴露私有成员的目的。这个也是闭包处理的一种方式
var obj= (function(){ var _age= 0; var func1= function(){ //... }; var func2= function(){ //... }; return { m1 : func1, m2 : func2 }; })();
使用上面的写法,外部代码无法读取内部的age变量。
console.info(obj.age);//undefined
-
放大模式:
如果一个??楹艽螅匦敕殖杉父霾糠?,或者一个??樾枰坛辛硪桓瞿??,这时就有必要采用"放大模式"(augmentation)。在原有的基础上扩展更多的方法。
var obj =(function (mod){ mod.func3 = function () { //... }; return mod;//方便方法连续调用 })(obj);
上面的代码为obj模块添加了一个新方法func3 (),然后返回新的obj??椋奖惴椒饔?。如何防止obj为null或undefined的情况? 可以采用宽放大模式。
5.宽放大模式(Loose augmentation):
? 在浏览器环境中,??榈母鞲霾糠滞ǔ6际谴油匣袢〉模惺蔽薹ㄖ滥母霾糠只嵯燃釉?。如果采用上面的写法,第一个执行的部 分有可能加载一个不存在的空对象,这时就要采用"宽放大模式"。
var obj =( function (mod){
//...
return mod;
})(window.obj|| {});//确保对象不为空
6.输入全局变量:
? 独立性是模块的重要特点,??槟诓孔詈貌挥氤绦虻钠渌糠种苯咏换ァN嗽谀?槟诓康饔萌直淞浚匦胂允降亟渌淞渴淙肽?椤?/p>
(function(window, undefined ) {
……
})(window);
这是jQuery框架的源码,将window对象作为参数传入,这样做除了保证??榈亩懒⑿?,还使得??橹涞囊览倒叵当涞妹飨?。
目前,通行的JavaScript??楣娣豆灿辛街郑篊ommonJS和AMD。
二,AMD、CMD、Require.js、sea.js、common.js、ES6的对比:
他们都是用于在??榛ㄒ逯惺褂玫模珹MD、CMD、CommonJs是ES5中提供的模块化编程的方案,import/export是ES6中定义新增的
-
AMD-异步??槎ㄒ?
AMD是RequireJS在推广过程中对模块定义的规范化产出,它是一个概念,RequireJS是对这个概念的实现,就好比JavaScript语言是对ECMAScript规范的实现。AMD是一个组织,RequireJS是在这个组织下自定义的一套脚本语言
define(['package/lib'], function(lib){ function foo(){ lib.log('hello'); return { foo: foo }; });
RequireJS:是一个AMD框架,可以异步加载JS文件,按照??榧釉胤椒ǎü齞efine()函数定义,第一个参数是一个数组,里面定义一些需要依赖的包,第二个参数是一个回调函数,通过变量来引用??槔锩娴姆椒?,最后通过return来输出。
注:RequireJS是一个依赖前置、异步定义的AMD框架(在参数里面引入js文件),在定义的同时如果需要用到别的??椋谧钋懊娑ㄒ搴眉丛诓问槔锩娼幸?,在回调里面加载
-
CMD-同步模块定义:
CMD是SeaJS在推广过程中对??槎ㄒ宓墓娣痘?,是一个同步??槎ㄒ澹荢eaJS的一个标准,SeaJS是CMD概念的一个实现,SeaJS是淘宝团队提供的一个??榭⒌膉s框架
define(function(require,exports,module){ //通过require 引入依赖(依赖就近原则) var $ = require('jquery'); var Spinning = require('./spinning'); }
通过define()定义,没有依赖前置,通过require加载jQuery插件,CMD是依赖就近,在什么地方使用到插件就在什么地方require该插件,即用即返,这是一个同步的概念
-
Require.js规范:
RequireJS是一个工具库,主要用于客户端的??楣芾?。它可以让客户端的代码分成一个个??椋迪忠觳交蚨釉?,从而提高代码的性能和可维护性。它的??楣芾碜袷?a target="_blank">AMD规范(Asynchronous Module Definition)。
RequireJS的基本思想是,通过define方法,将代码定义为???;通过require方法,实现代码的??榧釉?。
首先,将require.js嵌入网页,然后就能在网页中进行??榛喑塘?。
<script data-main="scripts/main" src="scripts/require.js"></script>
上面代码的data-main属性不可省略,用于指定主代码所在的脚本文件,在上例中为scripts子目录下的main.js文件。用户自定义的代码就放在这个main.js文件中。
define方法:定义???/strong>
define方法用于定义模块,RequireJS要求每个??榉旁谝桓龅ザ赖奈募?。
按照是否依赖其他模块,可以分成两种情况讨论。第一种情况是定义独立??椋此ㄒ宓哪?椴灰览灯渌??;第二种情况是定义非独立???,即所定义的模块依赖于其他??椤?/p>
(1)独立???/strong>
如果被定义的??槭且桓龆懒⒛??,不需要依赖任何其他???,可以直接用define方法生成。
define({ method1: function() {}, method2: function() {}, });
上面代码生成了一个拥有method1、method2两个方法的??椤?/p>
另一种等价的写法是,把对象写成一个函数,该函数的返回值就是输出的??椤?/p>
define(function () { return { method1: function() {}, method2: function() {}, }; });
后一种写法的自由度更高一点,可以在函数体内写一些模块初始化代码。
值得指出的是,define定义的模块可以返回任何值,不限于对象。
(2)非独立???/strong>
如果被定义的??樾枰览灯渌??,则define方法必须采用下面的格式。
define(['module1', 'module2'], function(m1, m2) { ... });
define方法的第一个参数是一个数组,它的成员是当前模块所依赖的??椤1热?,['module1', 'module2']表示我们定义的这个新??橐览涤趍odule1模块和module2??椋挥邢燃釉卣饬礁瞿?椋履?椴拍苷T诵小R话闱榭鱿?,module1??楹蚼odule2??橹傅氖?,当前目录下的module1.js文件和module2.js文件,等同于写成['./module1', './module2']。
define方法的第二个参数是一个函数,当前面数组的所有成员加载成功后,它将被调用。它的参数与数组的成员一一对应,比如function(m1, m2)就表示,这个函数的第一个参数m1对应module1??椋诙霾问齧2对应module2???。这个函数必须返回一个对象,供其他??榈饔谩?/p>
define(['module1', 'module2'], function(m1, m2) { return { method: function() { m1.methodA(); m2.methodB(); } }; });
上面代码表示新??榉祷匾桓龆韵?,该对象的method方法就是外部调用的接口,menthod方法内部调用了m1模块的methodA方法和m2??榈膍ethodB方法。
需要注意的是,回调函数必须返回一个对象,这个对象就是你定义的??椤?/p>
如果依赖的??楹芏?,参数与模块一一对应的写法非常麻烦。
define( [ 'dep1', 'dep2', 'dep3', 'dep4', 'dep5', 'dep6', 'dep7', 'dep8'], function(dep1, dep2, dep3, dep4, dep5, dep6, dep7, dep8){ ... } );
为了避免像上面代码那样繁琐的写法,RequireJS提供一种更简单的写法。
define( function (require) { var dep1 = require('dep1'), dep2 = require('dep2'), dep3 = require('dep3'), dep4 = require('dep4'), dep5 = require('dep5'), dep6 = require('dep6'), dep7 = require('dep7'), dep8 = require('dep8'); ... } });
下面是一个define实际运用的例子。
define(['math', 'graph'], function ( math, graph ) { return { plot: function(x, y){ return graph.drawPie(math.randomGrid(x,y)); } } }; );
上面代码定义的??橐览祄ath和graph两个库,然后返回一个具有plot接口的对象。
另一个实际的例子是,通过判断浏览器是否为IE,而选择加载zepto或jQuery。
define(('__proto__' in {} ? ['zepto'] : ['jquery']), function($) { return $; });
上面代码定义了一个中间???,该??橄扰卸箱榔魇欠裰С?strong>proto属性(除了IE,其他浏览器都支持),如果返回true,就加载zepto库,否则加载jQuery库。
require方法:调用???/strong>
require方法用于调用??椤K牟问雂efine方法类似。
require(['foo', 'bar'], function ( foo, bar ) { foo.doSomething(); });
上面方法表示加载foo和bar两个模块,当这两个模块都加载成功后,执行一个回调函数。该回调函数就用来完成具体的任务。
require方法的第一个参数,是一个表示依赖关系的数组。这个数组可以写得很灵活,请看下面的例子。
require( [ window.JSON ? undefined : 'util/json2' ], function ( JSON ) { JSON = JSON || window.JSON; console.log( JSON.parse( '{ "JSON" : "HERE" }' ) ); });
上面代码加载JSON??槭保紫扰卸箱榔魇欠裨С諮SON对象。如果是的,则将undefined传入回调函数,否则加载util目录下的json2??椤?/p>
require方法也可以用在define方法内部。
define(function (require) { var otherModule = require('otherModule'); });
下面的例子显示了如何动态加载??椤?/p>
define(function ( require ) { var isReady = false, foobar; require(['foo', 'bar'], function (foo, bar) { isReady = true; foobar = foo() + bar(); }); return { isReady: isReady, foobar: foobar }; });
上面代码所定义的???,内部加载了foo和bar两个???,在没有加载完成前,isReady属性值为false,加载完成后就变成了true。因此,可以根据isReady属性的值,决定下一步的动作。
下面的例子是??榈氖涑鼋峁且桓鰌romise对象。
define(['lib/Deferred'], function( Deferred ){ var defer = new Deferred(); require(['lib/templates/?index.html','lib/data/?stats'], function( template, data ){ defer.resolve({ template: template, data:data }); } ); return defer.promise(); });
上面代码的define方法返回一个promise对象,可以在该对象的then方法,指定下一步的动作。
如果服务器端采用JSONP模式,则可以直接在require中调用,方法是指定JSONP的callback参数为define。
require( [ "http://someapi.com/foo?callback=define" ], function (data) { console.log(data); });
require方法允许添加第三个参数,即错误处理的回调函数。
require( [ "backbone" ], function ( Backbone ) { return Backbone.View.extend({ /* ... */ }); }, function (err) { // ... } );
require方法的第三个参数,即处理错误的回调函数,接受一个error对象作为参数。
require对象还允许指定一个全局性的Error事件的监听函数。所有没有被上面的方法捕获的错误,都会被触发这个监听函数。
requirejs.onError = function (err) { // ... };
-
sea.js规范:
-
在 Sea.js 中,所有 JavaScript ??槎甲裱?CMD(Common Module Definition) ??槎ㄒ骞娣?。该规范明确了??榈幕臼樾锤袷胶突窘换ス嬖?。
在 CMD 规范中,一个??榫褪且桓鑫募?/strong>
-
使用seajs的步骤:
HTML里引入seajs
<script src="./lib/sea.js"></script>
入口:seajs.use("./main");
-
定义??閐efine:
function有三个参数:require参数用来引入别的???,exports和module用来导出??楣步涌?。
define(**function**(require, exports, module) { *//添加jquery依赖** \* **var** $ = require(**'jquery'**); **function** *Test*(container){ **this**.**container** = $(container); } *//提供模块的外部接口** \* module.exports = *Test*; *Test*.**prototype**.changeColor= **function** () { **var** v = **this**.**container**; v.css(**'color'**,**'red'**); } });
-
-
common.js规范:
CommonJS规范是通过module.exports定义的,在前端浏览器里面并不支持module.exports,通过node.js后端使用的。Nodejs端是使用CommonJS规范的,前端浏览器一般使用AMD、CMD、ES6等定义??榛⒌?/p>
exports.area = function (r) { return Math.PI * r * r; }; exports.circumference = function (r) { return 2 * Math.PI * r; };
输出方式有2种:
- 默认输出---module.exports
- 带有名字的输出---exports.func
-
ES6特性模块化:
AMD,CMD,CommoJs都是ES5里面的规范,下面的export/import是ES6里面的规范。通过export/import输入输出 例:
export default { props:['name'], data () { return{ } }, methods:{ increment(){ this.$emit('incre'); import('./../until') }, decrement(){ this.$emit('decre'); } } }