Logo

新人日誌

首頁關於我部落格

新人日誌

Logo

網站會不定期發佈技術筆記、職場心得相關的內容,歡迎關注本站!

網站
首頁關於我部落格
部落格
分類系列文

© 新人日誌. All rights reserved. 2020-present.

本文為「JS 101:函式」系列第 2 篇

JavaScript 入門必學:深入理解變數作用範圍(Scope)

最後更新:2026年3月10日JavaScript

在學習 JavaScript 的過程中,變數(Variable) 是你最常使用也最基礎的概念之一。

每當你要儲存資料、處理邏輯、或撰寫函式時,變數就會登場。

而在使用變數時,有一個非常重要但常被忽略的核心概念,那就是:變數的作用範圍(Scope)。

簡單來說,作用範圍就是「某個變數在程式的哪些地方能夠被讀取或使用」。

你可以把作用範圍想像成通行證制度:變數就像一個地區限定的票證或門票,只能在特定區域內使用。

例如,一張捷運票只能在進站後的車站區域內有效,離開閘門後就不能再用了。

同樣地,在程式中,變數也只能在它被「發行」的範圍內被讀取或操作,離開那個範圍,它就不再有效了。

什麼是作用範圍(Scope)?

在 JavaScript 中,當你宣告一個變數時,這個變數不會對整個程式「公開」。

它只能在某些地方被「看到」或「使用」,這個可見的範圍就叫做「作用範圍(scope)」。

你可以把它想像成變數有一張通行證,只能在特定的區域內通行。

離開那個範圍,這張票就無效了。

這樣的設計可以讓程式更有結構,變數之間不容易「打架」,也能避免無意間改錯值。

但為什麼需要這樣的設計呢?答案其實很簡單 —— 如果所有變數都能到處用,程式就會變得非常難懂,而且很容易出錯。

我們用一個購物網站的例子來說明。

想像你正在開發一個購物網站,程式裡有好幾個功能:計算購物車總金額、產生營收報表、處理結帳付款。

這些功能都需要用到變數,而「作用範圍」就是讓這些變數各自安好、不互相搞亂的關鍵。

避免同名變數互相干擾

在這個購物網站中,計算購物車總金額的程式碼用了一個變數叫 total,用來加總使用者選的商品價格。

同時,另一段負責營收報表的程式碼,也用了一個叫 total 的變數,來記錄整個月的總營收。

如果這兩個 total 沒有各自的範圍限制,而是放在同一個共用的範圍中,那麼它們就會互相影響。

可能你在處理購物車時改了 total,結果無意間也把報表的數值改掉,讓資料顯示錯誤,甚至導致 bug 難以追查。

有了作用範圍,這兩個 total 就可以各自存在於不同的區塊中,互不干擾。你可以自由地使用相同的變數名稱,也不用擔心一邊的邏輯會破壞到另一邊的資料。

降低變數除錯的難度

接下來,假設你在測試時發現購物車的 total 金額算出來是錯的。

你想找出是哪裡出了問題,但如果 JavaScript 沒有作用範圍,total 可以在整份程式的任何地方被宣告、改值或覆蓋。

這代表你必須把購物車、報表、結帳、甚至不相關的功能全部翻過一遍,才有可能查出是誰改了 total。

當程式碼只有幾十行時還能接受,但如果你的購物網站有幾千行程式碼,找一個變數被誰改過就像在大海撈針一樣痛苦。

有了作用範圍後,total 的活動空間就被限制住了。

如果 total 是在計算購物車的函式裡宣告的,那你就可以放心地知道:這個變數只存在這個函式裡,只有這裡面的程式碼會動到它。

這樣不但能更快鎖定問題的位置,也能大幅減少除錯的時間。

限制變數範圍,避免資料外洩

最後,當使用者要結帳時,程式需要處理信用卡卡號。

你會在結帳函式裡用一個變數 cardNumber 來暫存這筆資料:

function checkout(cardNumber) {
  // 結帳與付款邏輯
}

這個 cardNumber 是你只想在結帳流程中使用的變數,如果沒有作用範圍的限制,它就有可能「洩漏」到其他地方被看見或誤用。

舉例來說,其他功能的程式碼不小心讀取到了 cardNumber,結果把卡號印在營收報表裡,或是被傳到不該傳的地方,造成安全漏洞。

有了作用範圍後,cardNumber 只會存在於 checkout() 函式內部。

外部完全看不到它,也不能使用它。

當函式執行完畢後,這個變數就會自動消失。

這不只能保護敏感資料,也讓你更放心地在不同功能中使用各自的變數,而不怕彼此衝突或被誤改。

JavaScript 全域變數(Global Variables):整份程式都能使用的變數

在 JavaScript 中,主要有兩種常見的作用範圍:全域變數和區域變數。

當你在最外層(也就是所有函式或區塊之外)宣告一個變數,它就會成為全域變數(global variable)。

這種變數存在於整個程式的最外層,所以在任何地方幾乎都能使用它,無論你是在上面、下面、函式裡還是邏輯區塊中,都可以存取。

來看一個例子:

let greeting = "Hello!";

function sayHi() {
  console.log(greeting); // → Hello!
}

sayHi();
console.log(greeting); // → Hello!

這裡的 greeting 是在函式外部宣告的變數,因此它是全域變數。

你可以在函式內部讀取它,也可以在程式的其他地方使用它,這就是「全域」的意思。

使用全域變數的優點與風險

因為全域變數「到哪裡都能用」,所以在寫程式初期時會覺得它非常方便。

不管你在哪裡需要某個資料,只要在最外層宣告一次,全程都能直接使用,省下不少傳遞的麻煩。

但是,這種「到處都能用」的特性也可能造成問題,特別是當你的程式變得越來越大時:

不小心被其他地方改值

全域變數的最大風險就是,它可以被整個程式的任何地方修改。

這代表你在一個地方設定好的變數,可能會被另一個看似無關的程式片段改掉,造成錯誤卻難以發現。

隨著程式變大,變數變難管理

如果你把太多變數都設成全域的,久而久之你會搞不清楚誰用了什麼名稱,誰又不小心改了誰的值。

這會讓除錯變得非常困難。

程式容易互相干擾,尤其在多人協作時

你可能定義了一個全域變數叫 data,同事也剛好定義了一個一樣的 data,結果程式一跑,誰都搞不清楚現在的 data 是哪一個,產生難以預測的錯誤。

建議:盡量不要濫用全域變數

雖然全域變數在某些情況下很實用,例如設定常數(const APP_NAME = "MyApp")或需要整個程式共享的資料。

但在大多數情況下,更推薦使用在特定範圍內才會存在的變數,這樣可以讓你的程式更有組織,也更安全、更好除錯。

JavaScript 區域變數(Local Variables):只在特定範圍內有效的變數

和全域變數相反,區域變數是只在特定範圍內有效的變數。

這個範圍可以是兩種常見情況之一:

  1. 一個「函式」的範圍(function scope)
  2. 一對大括號 {} 組成的「區塊」範圍(block scope)

JavaScript 函式作用範圍(Function Scope)

如果你在一個函式內部宣告變數(使用 var、let 或 const),那這個變數只會存在於這個函式中。

函式從 { 開始,到 } 結束,形成一個完整的封閉範圍。

function sayHi() {
  let message = "Hello!";
  console.log(message);
}

sayHi();              // → Hello!
console.log(message); // 錯誤,message 在這裡不存在

上面這段程式中,message 是函式 sayHi 的區域變數,它只存在於函式內部。

當你在函式外部嘗試使用 message,就會出現錯誤,因為它的範圍只限於函式裡。

這種情況叫做函式作用範圍(function scope),是早期 JavaScript 變數行為的主要範圍類型,特別是當你使用 var 宣告變數時。

JavaScript 區塊作用範圍(Block Scope)

除了函式,JavaScript 中的 {} 大括號也可以形成一個區塊範圍,像是:

  • if 判斷式
  • for、while 迴圈
  • 任意以 {} 包起來的區塊

當你使用 let 或 const 宣告變數時,這些變數就只會存在於這對大括號 {} 裡面。

if (true) {
  let status = "logged in";
  console.log(status); // → logged in
}

console.log(status); // 錯誤,status 不存在於這裡

上面這個例子中,status 是用 let 宣告的,它只存在於 if 區塊內,出了這對 {} 就失效了,這就是所謂的區塊作用範圍(block scope)。

小提醒:var 不遵守區塊範圍!

值得注意的是,var 雖然也可以在區塊中宣告變數,但它不會受到區塊範圍的限制,而是會跳出區塊、回到最近的函式或全域範圍。

這點和 let、const 非常不同,後面會再詳細介紹。

if (true) {
  var name = "Alice";
}

console.log(name); // → Alice 雖然在 if 裡宣告,外面還是看得到

小結:函式範圍 vs 區塊範圍

範圍類型如何形成有效的變數宣告方式範圍限制範例
函式作用範圍用 function 宣告函式var / let / const僅在整個函式內有效
區塊作用範圍用 {} 包起來的條件、迴圈、區塊等let / const僅在 {} 中有效,外部無法存取
如何形成用 function 宣告函式
有效的變數宣告方式var / let / const
範圍限制範例僅在整個函式內有效
如何形成用 {} 包起來的條件、迴圈、區塊等
有效的變數宣告方式let / const
範圍限制範例僅在 {} 中有效,外部無法存取

注意:var 不會被區塊範圍限制,只會被函式範圍限制。

理解這兩種「區域範圍」的差異,能幫助你更有信心控制變數的使用範圍,也能避免常見的錯誤,例如:變數意外被覆蓋、變數跑出預期範圍等問題。

下一段,我們就會進一步比較 var、let、const 三者的差異,幫助你選擇最適合的宣告方式來寫出安全、穩定的 JavaScript 程式碼。

var、let、const:三種變數宣告方式的作用範圍差異

在 JavaScript 中,宣告變數有三種方式:var、let 和 const。

雖然它們都能用來建立變數,但它們的作用範圍其實不一樣,這會直接影響你寫出來的程式是安全還是容易出錯。

var 的範圍比較寬鬆(不受區塊限制)

在 JavaScript 中,var 是最早期就存在的變數宣告方式,它和後來加入的 let、const 不一樣,有一個非常特別且容易出錯的行為:

它沒有「區塊範圍」的概念,只有「函式範圍」與「全域範圍」。

也就是說,即使你在一個 {} 區塊裡使用 var 宣告變數,它也不會被侷限在這個區塊裡。

這種現象常常會讓人以為變數「只存在那塊裡」,結果卻在外部還能使用它,導致意料之外的行為。

範例:var 不會被限制在 {} 區塊中

if (true) {
  var message = "Hello!";
  console.log("區塊內:", message); // → 區塊內:Hello!
}

console.log("區塊外:", message);    // → 區塊外:Hello!

在這段程式碼中,我們在 if 區塊裡用 var 宣告了一個變數 message。

直覺上,你可能會以為它應該只存在於 if 裡,但實際上它「跑出區塊」,在外面依然能用。

這就是因為 var 不支援區塊作用範圍,只會看最近的「函式」或「全域」範圍。

如果這段程式碼寫在函式外部,那 message 就會直接變成全域變數。

var 不受區塊限制會帶來什麼問題?

這種範圍寬鬆的特性,看起來好像沒什麼,但實際上會造成很多潛在的錯誤,特別是:

你以為變數只在區塊內有效,其實它跑出來了

這可能讓你在區塊外不小心又使用到同一個變數名稱,結果資料被覆蓋,卻不知道是怎麼發生的。

程式可讀性變差,維護困難

當一個變數的範圍很大,你就很難判斷它是從哪裡來的、被誰改過、值是什麼時候變的。

範例:在 for 迴圈裡使用 var

for (var i = 0; i < 3; i++) {
  console.log("迴圈內:", i);
}

console.log("迴圈外:", i); // → 3

你可能會以為 i 是迴圈裡的變數,應該只能在 for 裡使用。

但因為用了 var,i 會「衝出」迴圈,在外面依然存在,而且值還是最後一次迴圈結束時的結果。

let 和 const 有真正的「區塊範圍」

在 JavaScript 的早期版本中,變數宣告只有 var 一種方式,它只能依附在「函式範圍」上,這會讓某些變數不小心跑到外面被使用,造成錯誤。

為了解決這個問題,JavaScript 在 ES6(2015年) 推出了兩個新的變數宣告方式:let 和 const。

這兩者最大的特點之一就是——它們擁有真正的「區塊作用範圍(block scope)」。

什麼是區塊範圍?

區塊(block)是指由一對大括號 {} 包起來的程式區段,像是:

  • if (...) { ... }
  • for (...) { ... }
  • while (...) { ... }
  • 或你自己用 {} 包起來的區塊

如果你用 let 或 const 在這些區塊裡宣告變數,這些變數就只會存在於該區塊內部,離開這對 {},變數就會「失效」。

範例:let 和 const 限定在區塊內有效

if (true) {
  let greeting = "Hi!";
  const name = "Amy";
  console.log(greeting, name); // → Hi! Amy
}

console.log(greeting); // 錯誤:greeting is not defined
console.log(name);     // 錯誤:name is not defined

在這個例子中,我們在 if 區塊內宣告了 greeting 和 name:

  • greeting 用 let 宣告
  • name 用 const 宣告

它們都只存在於 if 的 {} 區塊內,一旦程式跑出這個區塊,再使用這兩個變數就會出錯,因為它們已經「離線」了。

小結:為什麼推薦使用 let 和 const?

宣告方式區塊作用範圍函式作用範圍是否建議使用
var否是不建議
let是是推薦
const是是推薦
區塊作用範圍否
函式作用範圍是
是否建議使用不建議
區塊作用範圍是
函式作用範圍是
是否建議使用推薦
區塊作用範圍是
函式作用範圍是
是否建議使用推薦
  • 它們擁有明確的區塊範圍,不容易誤用
  • 它們的行為更符合人類直覺:「在 if 裡宣告,就只在 if 裡有效」
  • 它們能更清楚地表達你的意圖(是否允許修改)

因此,在現代 JavaScript 開發中,幾乎都使用 let 和 const,完全不再使用 var,除非你在維護舊版系統。

在理解 let 和 const 的區塊範圍之後,你的程式將會更有結構、更安全,也更容易閱讀與維護。

結語

搞懂作用範圍是成為 JavaScript 開發者的第一步。

無論是函式範圍還是區塊範圍,清楚知道變數在哪裡有效、哪裡無效,能幫助你寫出更乾淨且無錯誤的程式碼。

記住幾個關鍵點:

  • 使用 let 和 const 建立區塊範圍變數。
  • var 是舊式寫法,不受區塊範圍限制,容易造成變數意外外洩。
  • 全域變數方便但風險高,盡量限制變數的使用範圍。
  • 函式內部的變數外部看不到,區塊內部的 let/const 變數也一樣。

透過這些觀念,你的 JavaScript 寫作能力將更加穩固!

上一篇JavaScript 初學者教學:認識函式(Function)
下一篇JavaScript 函式值教學:從定義、使用到實戰應用
目前還沒有留言,成為第一個留言的人吧!

發表留言

留言將在審核後顯示。

JavaScript

目錄

  • 什麼是作用範圍(Scope)?
  • 避免同名變數互相干擾
  • 降低變數除錯的難度
  • 限制變數範圍,避免資料外洩
  • JavaScript 全域變數(Global Variables):整份程式都能使用的變數
  • 使用全域變數的優點與風險
  • 建議:盡量不要濫用全域變數
  • JavaScript 區域變數(Local Variables):只在特定範圍內有效的變數
  • JavaScript 函式作用範圍(Function Scope)
  • JavaScript 區塊作用範圍(Block Scope)
  • 小提醒:var 不遵守區塊範圍!
  • 小結:函式範圍 vs 區塊範圍
  • var、let、const:三種變數宣告方式的作用範圍差異
  • var 的範圍比較寬鬆(不受區塊限制)
  • let 和 const 有真正的「區塊範圍」
  • 小結:為什麼推薦使用 let 和 const?
  • 結語