在javascript中定義全局變量有2種方式,本質上是等價的,都是向window對象注入屬性或者方法。javascript
// global.js var g_name = "aty"; window.g_age = 25;
當global.js加載的時候,瀏覽器的全局對象window就會多出2個屬性:g_name和g_age。html
咱們編寫一個js工具類或者是js框架,一般有2種方式:
方式1:dateUtil.jsjava
(function(window) { var DateUtils = {}; DateUtils.toString = function(){ alert("toString"); }; // 全局變量 window.DateUtils = DateUtils; })(window);
這種方式是最經常使用的,好比JQuery、Underscore等框架都是採用這種結構編寫的。
數組
方式2:stringUtil.js瀏覽器
// 全局變量 var StringUtils = {}; StringUtils.toUpperCase = function(input){ alert("toUpperCase"); }
很顯然stringUtil.js和dateUtil.js都不符合AMD規範,如今咱們看看如何經過requireJS進行加載。工程目錄結構以下:框架
index.html main.js libs --dateUtil.js --stringUtil.js
index.html和main.js的實現代碼以下:函數
<!doctype html> <html> <head> <title>shim</title> <meta charset="utf-8"> <script data-main="main.js" src="./../requirejs-2.1.15.js"></script> </head> <body> <div id="div1" style="width:200px;height:200px;"></div> </body> </html>
requirejs.config({ baseUrl: 'libs' }); require(["dateUtil","stringUtil"], function(dateUtil,stringUtil) { alert(dateUtil===undefined);//true });
運行index.html,經過F12觀察:工具
很明顯dateUtil.js和stringUtil.js可以被requireJS正常加載,可是不能獲取到這2個模塊的返回值。咱們修改下index.html,給div註冊事件處理函數,並在事件處理函數中調用stringUtil.js提供的方法:requirejs
<!doctype html> <html> <head> <title>shim</title> <meta charset="utf-8"> <script data-main="main.js" src="./../requirejs-2.1.15.js"></script> <script> function test() { StringUtils.toUpperCase(); } </script> </head> <body> <div id="div1" style="width:200px;height:200px;" onclick="test();"></div> </body> </html>
點擊div1,能夠發現test()函數不會報錯。也就是說,requireJS加載不符合AMD規範的js文件,跟咱們直接在html經過<script>標籤加載,沒有太大的差異。js文件中引入的全局變量,依然會存在,依然可以正常使用。ui
下面咱們看下shim參數的使用方式,咱們將main.js修改以下:
requirejs.config({ baseUrl: 'libs', shim:{ dateUtil:{ deps:[], exports: 'DateUtils' }, stringUtil:{ deps:[], exports: 'StringUtils' } } }); require(["dateUtil","stringUtil"], function(dateUtil,stringUtil) { stringUtil.toUpperCase(); dateUtil.toString(); });
這段代碼能夠正常運行,能夠看到:shim參數可以幫助咱們以AMD模塊的方式,使用那些不符合AMD規範的模塊。下面接介紹下:deps和exports的含義。exports很好理解,就是模塊的返回值。main.js中exports的值,必定要與dateUtil.js和stringUtil.js中暴露出的全局變量名稱一致。很顯然dateUtil.js和stringUtil.js這2個模塊的返回值,就是暴露出的全局變量window.DateUtils和window.StringUtils,requireJS框架就是將這些全局變量的值返回,做爲模塊的返回結果。若是dateUtil.js或stringUtil.js中暴露了多個全局變量,那麼exports能夠指定其中任何的一個,做爲模塊的返回結果。不過通常的框架,都只會使用1個全局變量,這樣衝突的可能性會減小,畢竟全局變量越少越好。
上面咱們編寫的dateUtil.js和stringUtil.js,都不依賴於其餘js模塊,因此指定的deps是空數組。下面咱們編寫的aplugin.js和bplugin.js都依賴於模塊util.js。
//aplugin.js (function(window,util) { var a = {}; a.toString = function(){ alert("a="+util.add(1,2)); }; // 全局變量 window.a = a; })(window,util);
//bplugin.js var b = {}; b.toString = function(){ alert("b="+util.add(1,2)); }
//util.js var util = {}; util.add = function(v1,v2){ return v1+v2; };
main.js代碼以下,只有設置正確的依賴順序,使用的時候纔不會出問題。
requirejs.config({ baseUrl: 'libs', shim:{ dateUtil:{ deps:[], exports: 'DateUtils' }, stringUtil:{ deps:[], exports: 'StringUtils' }, aplugin:{ deps:["util"], exports: 'a' }, bplugin:{ deps:["util"], exports: 'b' } } }); require(["stringUtil","dateUtil","aplugin","bplugin"], function(string,date) { //string.toString(); //date.toString(); var aPl = require("aplugin"); var bPl = require("bplugin"); aPl.toString(); bPl.toString(); });
很顯然util.js也不符合AMD規範,若是A模塊依賴於B模塊,A模塊不符合AMD規範(使用的是全局變量),那麼B模塊也必須是使用全局變量,不然會報錯。即若是將util.js改爲符合AMD規範的寫法,那麼aplugin.js和bplugin.js都會因找不到util對象而報錯。
// 符合AMD規範的util.js define(function(){ function add(v1,v2) { return v1+v2; } return {"add":add}; });
最後咱們看下shim配置參數中init的做用。init能夠指定一個函數主要就是用來避免類庫之間的衝突。因爲不符合AMD規範的js文件,會使用全局變量。因此當加載多個模塊的時候存在名字衝突的可能。好比JQuery、UnderScore等框架都會提供一個noConflict()函數來避免名字衝突,noConflict()的實現原理能夠參考這篇文章。
咱們編寫一個不符合AMD規範的模塊conflict.js,使用了全局變量$E,並提供noConflict方法。
(function(window) { // 保存以前數據 var _$E = window.$E; var myplugin = {"name":"aty"}; myplugin.noConflict = function(){ window.$E = _$E; return myplugin; }; // 向全局對象註冊$E window.$E = myplugin; })(window);
將index.html修改以下,在requireJS加載以前,先定義一個全局變量$E。
<!doctype html> <html> <head> <title>shim</title> <meta charset="utf-8"> <script> var $E = "before"; </script> <script data-main="main.js" src="./../requirejs-2.1.15.js"></script> </head> <body> <div id="div1" style="width:200px;height:200px;" onclick="test();"></div> </body> </html>
main.js中代碼以下:
requirejs.config({ baseUrl: 'libs', shim:{ conflict:{ deps:[], exports: '$E', init:function(){ return $E.noConflict(); } } } }); require(["conflict"], function(mayConflict) { alert(mayConflict.name); alert(window.$E);//before });
運行index.html,能夠發現conflict.js可以與以前定義的全局變量$E共存,避免了衝突,這就是經過init實現的。若是沒有定義init,能夠看到alert(window.$E)打印的值是undefined。
原文:http://blog.csdn.net/aitangyong/article/details/44225859