一、在js中,變量的定義並不是以代碼塊作為作用域的,而是以函數作為作用域。也就是說,如果變量是在某個函數中定義的,那么,它在函數以外的地方是不可見的。但是,如果該變量是定義在if或者for這樣的代碼塊中,它在代碼塊之外是可見的。
二、在js中,術語“全局變量”指的是定義在所有函數之外的變量(也就是定義在全局代碼中的變量),與之相對的是“局部變量”,所指的是在某個函數中定義的變量。其中,函數內的代碼可以像訪問自己的局部變量那樣訪問全局變量,反之則不行。
三、下面是具體示例,請注意兩點:
1> 函數f()可以訪問變量global。
2> 在函數f()以外,變量local是不存在的。
var global = 1;
function f() {
var local = 2;
global ++;
return global;
}
測試結果如下:

還有一點要注意:如果我們聲明一個變量事沒有使用var語句,該變量就會被默認為全局變量。讓我們來看一個示例:
function f () {
local = 2;
}
undefined
local;
VM432:1 Uncaught ReferenceError: local is not defined
f();
undefined
local;
2
圖:

我們來看上面代碼發生了什么:首先,我們在函數f()中定義了一個變量local。在該函數被調用之前,這個變量並不存在。該變量會在函數首次被調用時創建,並被賦予全局作用域。這使得我們可以在該函數以外的地方訪問它。
四、最佳實踐:
1>盡量將全局變量的數量降到最低,以避免命名沖突。
2>最好總是使用var語句來聲明變量。
3>可以考慮使用“單一var”模式,即,僅在函數體內的第一行使用一個var來定義這個作用域中所有需要的變量。這樣一來,我們就能很輕松地找到相關變量的定義,並且在很大程度上避免了不小心污染全局變量的情況。
五、變量提升
舉例:
var a = 123;
function f(){
alert(a);
var a = 1;
alert(a);
}
f();
圖:

你可能會想當然的認為alert()第一次顯示的是123(即全局變量a的值),而第二次顯示的是1(即局部變量a)。但事實並非如此,第一個alert()實際上顯示的是undefined,這是因為函數域始終優先於全局域,所以全局變量a會覆蓋掉所有與它同名的全局變量,盡管在alert()第一次被調用時,a還沒有被證實定義(即,該值是undefined),但該變量本身已經存在於本地空間了。這種特殊的現象叫做提升。
結果如圖:


也就是說,當js執行過程進入新的函數時,這個函數內被聲明的所有變量所有變量都會被移動(或者說提升)到函數最開始的地方。另外,需要注意,被提升的只有變量的聲明,這意味着,只有函數體內聲明的這些變量在該函數執行開始時就存在,而與之相關的賦值操作並不會被提升,它還在原來的位置上。譬如,在原來的例子中,局部變量本身被提到了函數開始處,但並沒有在開始處就被賦值為1。這個例子可以被等價地改寫為:

當然,我們可以采用最佳實踐中提到過的單一var模式。在這個例子中,我們可以手動提升變量聲明的位置,這樣一來代碼就不會被js的提升行為所混淆了。
