在上一篇 變數與資料型別 中有介紹到變數,而變數還分為全域變數與區域變數,本篇將會介紹兩者的差異。

區域變數


首先用個函式來算一下梯形的面積:

1
2
3
4
5
6
function areaTr (upBase, downBase, height) {
var result = (upBase + downBase) * height / 2;
return result
}

console.log('梯形面積是' + areaTr(30, 40, 40)) // 印出 "梯形面積是1400"

上面的這一段沒什麼問題,如果在後面再加上一段 console.log(result) 的話,會發生什麼事?

1
2
3
4
5
6
7
function areaTr (upBase, downBase, height) {
var result = (upBase + downBase) * height / 2;
return result
}

console.log('梯形面積是' + areaTr(30, 40, 40));
console.log(result)

結果第二個 console 會出現錯誤,錯誤訊息是 result is not defined
為什麼找不到 result 呢?
首先要先了解一個原則,變數的最小有效區域只在函式中。
而在這個例子中,在函式裡透過 var 指定變數,第一個 console 執行完以後,變數就被用掉消失了,第二個 console 當然就找不到。
以上是一個區域變數的範例,而區域變數的好處是執行完後變數就會消失,可以節省記憶體。

全域變數


接著來看看在函式裡沒有透過 var 來宣告變數會怎樣。
在上面提到區域變數的範例中,原本第二個 console 不能執行。
那麼把 var 拿掉後:

1
2
3
4
5
6
7
function areaTr (upBase, downBase, height) {
result = (upBase + downBase) * height / 2;
return result
}

console.log('梯形面積是' + areaTr(30, 40, 40)); // "梯形面積是1400"
console.log(result) // 1400

結果第二個 console 可以執行了!?

這是因為如果不是由 var 宣告的變數,都會是全域變數。
所以即使變數 result 是在函式中宣告,但是因為沒有透過 var,所以一樣是全域變數。
而不在函式裡的變數,會一直都在。雖然一直都在可以隨時存取,但是這樣做比較浪費記憶體。
所以除非必要,否則在函式內的變數,都盡量透過 var 來宣告。

來看看如果計算梯形面積的函式,想要執行第二個 console 的話,還有以下方法:

透過 var 宣告變數,但不給值

在函式前再透過 var 宣告變數,但不給值。

1
2
3
4
5
6
7
8
9
var result;

function areaTr (upBase, downBase, height) {
result = (upBase + downBase) * height / 2;
return result
}

console.log('梯形面積是' + areaTr(30, 40, 40)); // "梯形面積是1400"
console.log(result) // 1400

如果是兩個變數都透過 var 宣告會是如何?

1
2
3
4
5
6
7
8
9
var result;

function areaTr (upBase, downBase, height) {
var result = (upBase + downBase) * height / 2;
return result
}

console.log('梯形面積是' + areaTr(30, 40, 40)); // "梯形面積是1400"
console.log(result) // undefined

第一個 console 一樣可以得到 “梯形面積是1400”,而第二個則是得到 undefined。
由於變數在函式中,以及透過 var 來宣告,所以符合區域變數的規範。
所以第一個 console 執行完,雖然最前面有透過 var 宣告變數,是一個全域變數,但是並沒有值,所以是 undefined。

這時候如果給它值,例如:

1
2
3
4
5
6
7
8
9
var result = 500;

function areaTr (upBase, downBase, height) {
var result = (upBase + downBase) * height / 2;
return result
}

console.log('梯形面積是' + areaTr(30, 40, 40)); // "梯形面積是1400"
console.log(result) // 500

基本上透過 var 來宣告,這兩個變數就可以視為兩個不同的東西了,要直接改變數的名字也印的出來結果。

提升


提升 (hoisting) 在 JavaScript 中又是一個坑。這在後面的一篇會提到,這邊則是稍微講一下。

在一般的情形下,執行以下的程式碼,其結果會是2

1
2
var a = 2;
console.log(a);

那麼如果在變數的前面也加上 console.log 呢?

1
2
3
console.log(a);
var a = 2;
console.log(a);

結果會是 undefined2,原因是 JavaScript 在執行時會是一行一行的執行,所以在執行第一行時找不到 a ,所以會是 undefined。

那麼在 function 中作這樣的事會是怎樣呢?
把呼叫執行的 hi() 放在 function 的前面

1
2
3
4
5
hi();

function hi() {
console.log('hello');
}

結果一樣可以印出 hello!!!
這是因為在 JavaScript 中,function 會優先執行,所以會作一個 hoisting,所以一樣可以執行。
但最好還是不要這樣作