前言
JavaScript中不同宣告變數的關鍵字會有不同的調用區域(也稱作用域)(Scope),我自己剛接觸JavaScript時,曾經沒有使用var 關鍵字來宣告變數,所以導致宣告的變數無論在哪裡都會是全域變數,這會很容易造成後面誤用或干擾到區域變數,進而成為系統程式bug的原因。因此,對於變數的作用域範圍必須要有所掌握,才可以寫出具有穩定性的程式!
關鍵字var let const 的比較
var | let | const |
---|---|---|
變數宣告方式 | 變數宣告方式 (來宣告在可能會有再次賦值的變數) | 常數宣告方式 (如同JAVA的關鍵字final),像是const PI = 3.14 ,且const宣告變數時就會有初始化的動作,若之後再次賦值,就發生Uncaught TypeError: Assignment to constant variable 的錯誤喔! |
函式範圍來決定變數的作用域 (function scope),且要注意會有變數提升(Variables Hoisting)的特性 | 有效作用域是根據以區塊(block)來決定,稱為block scope,區塊就是大括號{} 或小括號() 裡面的範圍 ,不會有 hoisting 的狀況 |
如同let的作用域一樣,也是透過區塊(block)來決定來決定作用域範圍,不會有 hoisting 的狀況 |
可以重複宣告 | 不可重複宣告 | 不可重複宣告 |
宣告前存取或覆值就會回傳undefined | 宣告前存取或覆值會直接出現ReferenceError,並終止程式執行 | 宣告前存取或覆值會直接出現ReferenceError,並終止程式執行 |
ES6後比較少用 | 常用來宣告for迴圈中的循環變數 | 可以使用在陣列、物件或函式等參照類型的使用 |
ES6之後都漸漸使用let來宣告變數,主要是希望開發的專案能具有穩定性及可讀性
- let來宣告變數不會汙染到全域物件,而且可以避免區域變數覆蓋全域變數及循環變數洩漏為全域變數,下面的程式碼為用var來宣告變數可能會遇到的狀況
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20//區域變數覆蓋全域變數
var tmp = 'test';//Global Variable
function f(){
glo_tmp = 'global';//Global Variable
//var glo_tmp = 'global123'; //如果沒有這行var宣告變數,glo_tmp就是全域變數,可以透過window.glo_tmp取得
console.log(tmp); //undefined,下面宣告的var tmp = 'new';,var tmp;會自動提升到函式最上面做初始化的動作;
if(true){
var tmp = 'new';
}
console.log(tmp);//new
};
f();
console.log(tmp);//test
//循環變數洩漏為全域變數
console.log(window.glo_tmp);
var s = 'test';
for(var i=0; i<s.length; i++){
console.log(s[i]);
}
console.log(i);// 4- 如果var宣告變數不是在函數當中的話,就會成為全域物件的變數 ; let宣告的變數有效範圍則是在if的大括號裡面而已
1
2
3
4
5
6if(true) {
var v = 'v';
let a = 'a';
}
console.log(v); //v
console.log(a); //Uncaught ReferenceError: a is not defined
在沒有var宣告情況下都視為全域變數,像是下面的glo_tmp,同時也是wondow物件的一個屬性,所以可以透過window.glo_tmp取得值
- 可以使用 delete glo_tmp來刪除物件屬性,並會return一個true
- 盡可能避免此種宣告方式,很容易造成系統上面的bug
1 | function f(){ |
- 只要存取的變數在函式當中有宣告,就算變數的存取比宣告早,也不會變成是全域變數的存取,但只要函式裡面都沒有做var宣告變數,最後印出來的tmp就會是hello
1 | var tmp = 'test';//Global Variable |