一、盡量少用全域物件
全域變數的問題在於,你的JavaScript應用程式和web頁面上的所有程式碼都共享了這些全域變量,他們住在同一個全域命名空間,所以當程式的兩個不同部分定義同名但不同作用的全域變數的時候,命名衝突在所難免。
web頁麵包含不是該頁面開發者所寫的程式碼也是比較常見的,例如:
比方說,該第三方腳本定義了一個全域變量,叫做result;接著,在你的函數中也定義一個名為result的全域變數。結果就是後面的變數覆蓋前面的,第三方腳本就一下子嗝屁啦!
因為,你不小心,在程式碼的某處修改了全域變量, 會導致依賴全域變數的其它模組出錯。而且出錯原因難調試,難找到。
再者就是,網頁運行肯定用到window對象,瀏覽器引擎又要遍歷一次window的屬性,效能下降。
var i,n,sum//globals function averageScore(players){ sum =0; for(i = 1, i = player.length; i<n; i++){ sum += score(players[i]); } return sum/n; }
保持這些變數為局部變量,僅將其作為需要使用它們的程式碼的一部分。
function averageScore(players){ var i,n,sum; sum =0; for(i = 1, i = player.length; i<n; i++){ sum += score(players[i]); } return sum/n; }
在browser中,this關鍵字會指向全域的window物件
JavaScript 的全域命名空間也被揭露為在程式全域作用域中可以存取的全域對象,該物件作為 this 關鍵字的初始值。在 Web 瀏覽器中,全域物件被綁定到全域的 window 變數。新增或修改全域變數會自動更新全域物件。
this.foo; //undefined foo ="global foo"; //"global foo" this.foo; //"global foo"
類似地,更新全域物件也會自動更新全域命名空間:
var foo ="global foo"; this.foo; //"global foo" this.foo ="changed"; foo; //"changed"
兩種用來改變全域物件的方式,透過var關鍵字聲明以及給全域物件設定屬性(透過this關鍵字)
透過全域物件進行針對目前運作環境的特性偵測(Feature Detection),例如在ES5中提供了一個JSON物件用來操作JSON數據,那麼可以透過if(this.JSON)來判斷目前運作環境是否支持JSON
if(!this.JSON){ this.JSON ={ parse:..., stringify:... } }
二、如何避免全域變數
方法一:只建立一個全域變數。
MYAPP.stooge = { "first-name": "Joe", "last-name": "Howard" }; MYAPP.flight = { airline: "Oceanic", number: 815, departure: { IATA: "SYD", time: "2004-09-22 14:55", city: "Sydney" }, arrival: { IATA: "LAX", time: "2004-09-23 10:42", city: "Los Angeles" } };
方法二:使用模組模式
var serial_maker = function ( ) { // Produce an object that produces unique strings. A // unique string is made up of two parts: a prefix // and a sequence number. The object comes with // methods for setting the prefix and sequence // number, and a gensym method that produces unique // strings. var prefix = ''; var seq = 0; return { set_prefix: function (p) { prefix = String(p); }, set_seq: function (s) { seq = s; }, gensym: function ( ) { var result = prefix + seq; seq += 1; return result; } }; }( ); var seqer = serial_maker( ); seqer.set_prefix = 'Q'; seqer.set_seq = 1000; var unique = seqer.gensym( ); // unique is "Q1000"
所謂模組模式,就是創建一個函數,該函數包括,私有變數和特權對象,特權對象的內容是,利用閉包能存取私有變數的函數,最後傳回特權物件。
首先,方法二,不僅可以當作全域變數用,也可以用在局部宣告全域變數。因為就算你在不知道某個地方修改了seqer,就會立即報錯,因為這是個對象,不是字串。
方法三:零全域變數
零全域變數其實是為了適應一小段封閉程式碼而採取的局部變數處理方式,只適合在一些特殊場景中使用。最常見的是一些不會被其他腳本訪問到的完全獨立的腳本。
使用零全域變數的方式需要採用立即執行函數,用法如下。
( function ( win ) { 'use strict' ; var doc = win.document ; //在此定义其他的变量并书写代码 } )
三、意外的全域變數
由於JavaScript的兩個特徵,不自覺地創建出全域變數是出乎意料的容易。首先,你可以甚至不需要宣告就可以使用變數;第二,JavaScript有隱含的全域概念,代表你不宣告的任何變數都會成為一個全域物件屬性。參考下面的程式碼:
function sum(x, y) { // 不推荐写法: 隐式全局变量 result = x + y; return result; }
此段程式碼中的result沒有聲明。程式碼照樣運作正常,但在呼叫函數後你最後的結果就多一個全域命名空間,這可以是一個問題的根源。
經驗法則是始終使用var聲明變量,正如改進版的sum()函數所演示的:
function sum(x, y) { var result = x + y; return result; }
另一個建立隱式全域變數的反例就是使用任務鏈進行部分var宣告。下面的片段中,a是本地變量但是b確實全局變量,這可能不是你希望發生的:
// 反例,勿使用 function foo() { var a = b = 0; // ... }
此现象发生的原因在于这个从右到左的赋值,首先,是赋值表达式b = 0,此情况下b是未声明的。这个表达式的返回值是0,然后这个0就分配给了通过var定义的这个局部变量a。换句话说,就好比你输入了:
var a = (b = 0);
如果你已经准备好声明变量,使用链分配是比较好的做法,不会产生任何意料之外的全局变量,如:
function foo() { var a, b; // ... a = b = 0; // 两个均局部变量 }
然而,另外一个避免全局变量的原因是可移植性。如果你想你的代码在不同的环境下(主机下)运行,使用全局变量如履薄冰,因为你会无意中覆盖你最初环境下不存在的主机对象
总是记得通过var关键字来声明局部变量
使用lint工具来确保没有隐式声明的全局变量
以上就是对javascript的全局变量介绍,希望对大家的学习有所帮助。