在過去幾天的文章中,我們學會了如何宣告變數,也學會了把程式碼打包成函式(Function)來重複使用,但隨著你的程式碼越寫越多,你可能會遇到一個狀況:
「明明我已經在程式碼裡面寫了let score = 100;,為什麼在另外一個地方要用它的時候,控制台卻亮起紅字,寫說ReferenceError: score is not defined(找不到這個變數)?」
這不是你的瀏覽器壞掉了,而是你遇到了JavaScript裡最經典的陷阱:作用域(Scope),今天我們就用最簡單的方式,直接搞懂變數的作用範圍。
簡單來說 作用域就是「變數的生存邊界與活動範圍」。
在JavaScript中,變數並不是宣告之後就能在全網頁的所有地方被讀取,每一個變數都有它專屬的「區域」,一旦超出了它的區域,它就會直接消失,程式也會當作完全不認識它。
現代JavaScript的生存區域,主要分為以下兩類:
{ }(例如if判斷式或for迴圈)給包住,它就是區域變數。如果覺得範圍不好記,只要記住這個原則:
<!DOCTYPE html>
<html lang="zh-Hant">
<head>
<meta charset="UTF-8">
<title>Day28 JavaScript 作用域基礎</title>
</head>
<body>
<h1 style="text-align: center;">請打開 Console 觀察變數的生存邊界</h1>
<script>
// 1. 全域變數:大家都認識它
const globalName = "聖騎士亞瑟"; // 宣告在最外層
function showHero() {
// 內層看得到外層:函式內部可以完美抓到外面的變數
console.log("函式內部讀取全域變數:" + globalName);
}
showHero(); // 印出: 函式內部讀取全域變數:聖騎士亞瑟
// 2. 區域變數:外面的人抓不到它
function getWeapon() {
const weaponName = "王者之劍"; // 宣告在函式內部(內層)
console.log("函式內部讀取區域變數成功:" + weaponName);
}
getWeapon(); // 執行函式,內部讀取沒問題,印出: 王者之劍
// 恐怖雷區:在最外層嘗試抓取裡面的區域變數
// 外層看不到內層!這行會直接噴錯,導致程式中斷!
console.log("在最外層嘗試偷看武器:" + weaponName);
// 控制台噴錯:ReferenceError: weaponName is not defined
</script>
</body>
</html>

當你將這段程式碼在瀏覽器中運行並打開控制台(Console)時,你會看到兩行成功的輸出,以及一行紅色的錯誤
globalName因為住在最外面,所以當showHero()函式在內部跟它打招呼時,它能完美回應,順利把名字印出來。weaponName是在getWeapon()的大括號內誕生的,它的地盤就只限於此,當函式執行完畢後,這把武器在記憶體中就被銷毀了,因此當最後一行的console.log在最外層想要讀取它時,大腦就會因為「越界搜尋失敗」而直接罷工,拋出找不到變數的錯誤。今天我們認識了JavaScript的核心內功 作用域(Scope)。
在實際開發上,我們應該盡量「減少使用全域變數」,多用「區域變數」,因為如果都是全域變數,程式的每個地方都能隨意修改它,就很容易引發難以追查的數據混亂。
明天(Day 29),我們將進入JS系列的最後一天:陣列與物件的常用操作方法,我們要學習如何用最簡單的內建語法(如push、filter),對海量的清單資料進行更高級的篩選與增減,明天見。