變量的作用域
這是一個至關重要的為題。特別是當我們從別的語言轉向JS的時,必須要明白這一點,即在Javascript中,變量的定義并不是以代碼塊作為作用域的,而是以函數作為作用域的。也就是說,如果變量是在某個函數中定義的,那么它在函數以外的地方是不可見的。而如果變量是定義在if或者for這樣的代碼塊中的,它在代碼塊以外是可見的。另外,在Javascript中,術語“全局變量”指的是定義在所有函數之外的變量(也就是定義在全局代碼中的變量),與之相對的是“局部變量”,所指的則是在某個函數中定義的變量。其中,函數內的代碼可以像訪問自己的局部變量那樣訪問全局變量,反之,則不行。
下面來看一個具體演示,請注意兩點:
- 函數f()可以訪問變量global;
- 在函數f()以外,變量local是不存在的。
var global = 1;
function f() {
var local = 2;
global ++;
return global;
}
f(); // 2
f(); // 3
local; // local is not defined
這里還有一點很重要,如果我們聲明一個變量時沒有使用var語句,該變量就會被默認為全局變量。
最佳實踐
- 盡量將全局變量的數量降到最低,以避免命名沖突,因為如果有兩個人在同一腳本的不同函數中使用了相同的全局變量名,就很容易到很容易導致不可預測的結果喝難以觀察的bug
- 最好總是使用var語句來聲明變量
- 可以考慮使用“單一var”模式,即,僅在函數體內的第一行使用一個var來定義這個作用域中所有需要的變量。這樣一來,我們就能很輕松地找到相關變量的定義,并且在很大程度上避免了不小心污染全局變量的情況。
變量提升
下面我們來看一個很有趣的例子,它顯示了關于局部和全局作用域的另一個重要問題。
var a = 123;
function f(){
alert(a);
var a = 1;
alert(a);
};
f();
你可能會想當然的認為alert()第一次顯示的是123(也就是全局變量a的值),而第二次顯示的是1(即局部變量a)。但事實上并非如此,第一個alert()實際上顯示的是undefined,這是應為函數域始終優(yōu)先于全局域,所以局部變量a會覆蓋掉所有與它同名的全局變量,盡管在alert()第一次被調用時,a還沒有被正式定義(即該值為undefined),但該變量本身已經存在于本地空間了。這種特殊的現象叫做提升。
也就是說,當Javascript的執(zhí)行過程進入新的函數時,這個函數內被聲明的變量都會被移動(或者說被提升)到函數最開始的地方。這個概念很重要,必須牢記。另外需要注意的是,被提升的只有變量的聲明,這意味著,只有函數體內聲明的這些變量在該函數執(zhí)行開始時就存在,而與之相關的賦值操作并不會被提升,它還在原來的位置上。譬如在上面的例子中,局部變量本身被提升到了函數開始處,但并沒有在開始處就被賦值為1。這個例子可以等價為:
var a = 123;
function f() {
var a;
alert(a); // undefined
var a =1;
alert(a) // 1
}