JavaScript中沒有塊級範圍的概念。這意味著在塊語句中定義的變數,實際上是在包含函數中而非語句中建立的。
function outputNumbers(count){ for(var i = 0; i < count; i++){ alert(i); } console.log(i);}outputNumbers(2);//彈出0,1輸出2//變數i是定義在outputNumbers()的使用中的物件中的,因此從它有定義開始,就可以在函數內部隨時訪問它。
函數中的多重聲明,對於多次聲明同一個變數,JavaScript只會對後續的聲明視而不見。
function outputNumbers(count){ for(var i = 0; i < count; i++){ alert(i); } var i; console.log(i);}outputNumbers(2);//彈出0,1輸出2
解決過程
【過渡寫法】先建立一個匿名函數,並把匿名函數賦值給變數someFunction,然後通過在函數名稱後面添加一對圓括弧來調用函數。
var someFunction = function(){
//這裡是塊級範圍
};
someFunction();
【錯誤寫法】這種匿名函數直接跟圓括弧會報錯,因為JavaScript將function關鍵字當作一個函式宣告的開始,而函式宣告後面不能跟圓括弧
function(){
//這裡是塊級範圍
}();//出錯
【正確寫法】而函數運算式的後面可以跟圓括弧,要將函式宣告轉換成函數運算式,只要給函數整體套上一個圓括弧即可。
(function(){
//這裡是塊級範圍
})();
//定義並立即調用了一個匿名函數。將函式宣告包含在一對圓括弧中,表示它實際上是一個函數運算式。而緊隨其後的另一對圓括弧會立即調用這個函數。
解決辦法
【設定塊級範圍】在重寫後的outputNumbers()函數中,在for迴圈外部插入了一個私人範圍。在匿名函數中定義的任何變數,都會在執行結束時被銷毀。因此,變數i只能在迴圈中使用。
function outputNumbers(count){ (function(){ for(var i = 0; i < count; i++){ alert(i); } })() console.log(i);}outputNumbers(2);//彈出0,1,然後報錯,提示i is not defined
應用情境
這種技術經常在全域使用域中被用在函數外部,從而限制向全域範圍中添加過多的變數和函數。通過建立私人範圍,每個開發人員既可以使用自己的變數,又不必擔心搞亂全域範圍。
(function(){ var now = new Date(); if(now.getMonth() === 0 && now.getDate() === 1){ alert("happy new year!"); }})();//代碼中的變數now是匿名函數中的局部變數,不必在全域範圍中建立它。
好處
這種做法可以減少閉包佔用的記憶體問題,因為沒有指向匿名函數的引用,只要匿名函數執行完畢,就可以立即銷毀其範圍鏈了。
JS 模仿塊級範圍
無塊級範圍及如何類比塊級範圍
javascript是沒有塊級範圍的,如下可驗證:
if(true){ var name = "xiaofei";}console.log(name); //xiaofei for(var i = 0; i < 10; i++){ //do something}console.log(i); //10
那如何類比塊級範圍呢?可以利用匿名函數來類比塊級範圍
(function(){//此處定義的變數會在運行結束後被銷毀})(); //看一個例子:function fun(n){ (function(){ for(var i = 0; i < n; i++){ //do something } })(); console.log(i); //無法訪問 發生錯誤}
解釋:fun函數內部的匿名函數運行完畢後內部的變數立即被銷毀了,所以在匿名函數外邊訪問不到i
還要注意的是在fun函數內部建立了一個匿名函數實質是建立了一個閉包,但是這個閉包沒有付給其他變數,就沒有存在引用,
所以在它執行完後立即被銷毀
Javascript之匿名函數(模仿塊級範圍)
JavaScript中是沒有塊級範圍概念的。也就是說,在塊級語句中定義的變數,實際上是在包含函數中(外部函數)而非語句中建立的。
function outputNumber(count){ for(var i=0;i<1000;i++){ alert(i); } alert(i); //count }
該函數在java、C#等語言中,變數i只會在for迴圈語句中有定義,迴圈結束,i也就被銷毀了。但在JavaScript中,變數i是定義在outputNumber()使用中的物件中的,因此在它定義開始,就可以在函數內部訪問它。即使重新聲明同一個變數,也不會改變它的值。
function outputNumber(count){ for(var i=0;i<1000;i++){ alert(i); } var i; //重新聲明變數 alert(i); //count }
匿名函數可以用來模仿塊級範圍並避免這個問題,用作塊級範圍(也稱私人範圍)的匿名函數的文法如下:
(function(){ //這是塊級範圍 })()
以上代碼定義變調用了一個匿名函數,將函式宣告包含在一個小括弧裡面,表示它是個函數運算式。緊跟其後的另一對小括弧會立即調用這個函數。
無論什麼時候,只要臨時需要一些變數,就可以用私用範圍,例如:
function outputNumber(count){ (function(){ for(var i=0;i<1000;i++){ alert(i); })(); alert(i); //導致一個錯誤 }
這樣,我們在for迴圈外部插入了一個私人範圍。在匿名函數中定義的任何變數,都會在執行結束時被銷毀。
這種技術經常在全域範圍中被用在函數外部,從而限制向全域範圍中添加過多的變數和函數。
一般來說,我們應該盡量減少向全域範圍中添加變數和函數。
這種做法可以減少閉包佔用記憶體的問題,因為沒有指向匿名函數的引用,只要函數執行完畢,就可以立即銷毀其範圍鏈。