1. 程式人生 > >防止js全域性變數汙染方法總結-待續

防止js全域性變數汙染方法總結-待續

javaScript 可以隨意定義儲存所有應用資源的全域性變數。但全域性變數可以削弱程式靈活性,增大了模組之間的耦合性。
在多人協作時,如果定義過多的全域性變數 有可能造成全域性變數衝突,也就是全域性變數汙染問題,以下是兩種解決辦法

一.定義全域性變數名稱空間
只建立一個全域性變數,並定義該變數為當前應用容器,把其他全域性變數追加在該名稱空間下

var MY={};
my.name={
big_name:"zhangsan",
small_name:"lisi"
};
my.work={
school_work:"study",

family_work:"we are"
};
二 . 利用匿名函式將指令碼包裹起來

(function(){
var exp={};
var name="aa";
exp.method=function(){
return name;
};
window.ex=exp;
})();

前言

記得long long ago,剛剛開始寫JS的時候,我喜歡寫一些函式在JS檔案裡邊,然後通過script標籤引進來,在DOM節點上繫結onclick等事件,看了很多人寫的程式碼,也大多是這樣。

後來會發現,當專案小的時候這麼做為了快速開發是可以接受的,然而當很多人一起開發一個Javascript大應用的時候,你會發現不同的程式碼風格跟全域性變數會導致很多衝突,這是一個很痛苦的事情。

曾經的經歷

用過jQuery的人就知道其主要的變數符號就是$,沒錯!因此很多專案的開發人員也要學,就自己把$定義成別的含義了,我心裡對其是無敵的鄙視跟厭惡。

我曾經拿過一個專案使用jQuery的,然後上頭要我使用一個已有的富文字編輯器,這樣就有兩個JS檔案了

jquery.js和editor.js,於是我要開始寫該頁面的邏輯了,我發現editor.js裡邊自定義了$符號,我原本想要把它直接替換成別的標誌符,但是悲劇的是,它還有一些外掛也會用到,混亂的結構導致我花了很多時間去解決這個衝突。

全域性Window

我們都知道,在檔案中直接定義的變數跟函式(不巢狀在任何域底下的)都是屬於全域性的,也就是都在當前頁面的window變數底下。例如:

Js程式碼  收藏程式碼
  1. function test1(){  
  2. }  
  3. var name;  
  4. function test2(){  
  5.     i = 1;  
  6. }  

上邊程式碼中的name,test1,test2和i都是屬於window底下的全域性變數,也就是可以通過以下三種辦法訪問到它們:

1.直接訪問name,test1()等;

2.使用window["name"], window['test1']()等;

3.使用window.name,window.test1()等。

注意:上邊程式碼中的i雖然是在test2函式裡邊才出現的,因為其前面沒有使用var關鍵字,直譯器會認為它在test2的上一層定義的,依次查詢上一層,直到找到window全域性,如果發現還是未定義,那麼將其掛在window底下成為了全域性變數。

所以你直接定義的函式通通都掛到了window底下,這就是一種汙染了,當很多人定義各種變數跟函式,你又得同時引入進來的時候,這個衝突的概率就變大了。

減少汙染

那為了避免過多這樣的衝突,以及模組之間的耦合性更低,需要減少這樣的汙染。

此時我們會想,那不要把變數定義在全域性唄,採用類似C++的名稱空間,Java的包的思路就行啦。

首先就是將不同的模組劃入到不同的全域性“包”(這裡的包的概念實際上就是一個Javascript物件而已)。

例如,程式設計師A為全域性新增一個A變數,然後他把自己定義的函式/變數全部掛到A底下,這樣就跟程式設計師B所定義的隔離了。

再者我們可以使用函式域來隔離一些區域性變數的衝突,比如說程式設計師A寫的程式碼如下:

Js程式碼  收藏程式碼
  1. (function(obj){  
  2.     /* 在這裡邊就與外邊隔離了,定義的區域性變數不會與外界干擾 */  
  3.     /* 為了跟外界達到共享的目的,還可以為其加入引數,例如obj,在最後呼叫的時候把相關的引數傳進來,例如下邊的window */  
  4.     var A = {};//定義一個A包  
  5.     var tmp;//臨時變數  
  6.     A.i = 1;//定義這個包裡邊的i變數  
  7.     A.func = function(){alert('I am A');};  
  8.     obj.A = A;/* 把A包掛到obj底下 */  
  9. })(window);  

當離開了這個函式域之後,tmp等區域性變數被銷燬(只要不要存在在閉包裡邊),程式設計師A定義的東西通通掛到了變數window.A底下,從而減少了很多汙染,避免了不必要的衝突。

回到過去

再次回到剛剛提過的那個經歷,如果我現在為editor.js整個包圍在function裡邊,通過這種方式把$給隱藏在一個包裡邊,在它的其他控制元件中也採取這樣的做法,當然還要做一小點改動:

Js程式碼  收藏程式碼
  1. /* editor.js */  
  2. (function(obj){  
  3.     /* 原先editor裡邊的內容 */  
  4.     /* 裡邊有定義了自己的$標誌 */  
  5.     obj.editor = obj.editor || {};//如果沒有editor物件,則生成一個空物件  
  6.     obj.editor.$ = $;//把$掛在全域性的editor物件上  
  7. })(window);  
Js程式碼  收藏程式碼
  1. /* 其他控制元件.js */  
  2. (function(obj){  
  3.     var $ = obj.$;//把$恢復  
  4.     /* 原先控制元件的內容 */  
  5. })(window.editor);  

當然咯,如果editor.js有些功能需要暴露到全域性的話,還需要將其進一步的掛在editor變數底下,這裡只是一個示範。

本篇總結

很多框架都採用了這種做法減少全域性汙染,可能很多人一開始對這種做法有疑惑,這裡只是個人理解拿出來分享一下,繼續歡迎交流。