Logo

新人日誌

首頁關於我部落格

新人日誌

Logo

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

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

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

初學者指南:深入了解 JavaScript 的函式作用域與區塊作用域

最後更新:2024年10月17日JavaScript

在學習 JavaScript 的過程中,理解「作用域」(Scope)的概念是至關重要的。

作用域決定了變數和函式在程式中的可見性和生命週期。

JavaScript 的作用域主要分為兩種:函式作用域(Function Scope)和 區塊作用域(Block Scope)。

本文將為新手詳細介紹這兩種作用域的概念、差異,以及如何在實際開發中正確使用它們。

閱讀本文前,建議先具備相關概念:初學者指南:深入了解 JavaScript 的建立期與執行期


什麼是作用域?

作用域是指變數或函式在程式中可被訪問的範圍。理解作用域有助於:

  • 避免變數命名衝突:確保不同作用域中的變數不會互相影響。
  • 管理變數的生命週期:控制變數何時被創建和銷毀。
  • 提高程式碼的可讀性和維護性:清晰地組織程式結構。

函式作用域(Function Scope)

定義

函式作用域是指在「函式」內部宣告的變數,只有在該函式內部可見和可訪問。

傳統上,JavaScript 使用 var 關鍵字宣告的變數就是具有函式作用域。

特點

  • 作用範圍限制在函式內部:變數在函式內部宣告後,無法在函式外部訪問。
  • 變數提升(Hoisting):使用 var 宣告的變數會被提升到函式作用域的頂部,初始化為 undefined。

範例

範例 1:函式內部的變數

function greet() {
  var message = "Hello, World!";
  console.log(message); // 輸出:Hello, World!
}

greet();
console.log(message); // ReferenceError: message is not defined

解釋:

  • 變數 message 在函式 greet 內宣告,只有在該函式內部可訪問。
  • 在函式外部訪問 message 會拋出錯誤,因為它不在全域作用域內。

變數提升

function test() {
  console.log(a); // 輸出:undefined
  var a = 10;
  console.log(a); // 輸出:10
}

test();

解釋:

  • var a = 10; 中的 a 被提升到函式的頂部,但未賦值,因此第一次輸出為 undefined。
  • 之後 a 被賦值為 10,第二次輸出為 10。

變數提升帶來的問題

  • 意外的 undefined:因為變數提升,可能在變數宣告之前就訪問到該變數,導致輸出 undefined。
  • 難以調試:變數提升可能讓程式碼的執行順序變得不直觀,增加調試的難度。

區塊作用域(Block Scope)

定義

區塊作用域是指在一對花括號 {} 所包圍的區塊內宣告的變數,其作用範圍僅限於該區塊內。

ES6 引入了 let 和 const 關鍵字,使得 JavaScript 支援區塊作用域。

特點

  • 作用範圍限制在區塊內部:變數在區塊內宣告後,無法在區塊外部訪問。
  • 不會提升或在提升時不會初始化:let 和 const 宣告的變數在建立期被創建但不初始化,在宣告之前訪問會拋出錯誤。
  • 暫時性死區(Temporal Dead Zone,TDZ):從區塊的開始到變數宣告為止的區域,無法訪問該變數。

範例

範例 1:區塊內部的變數

{
  let x = 10;
  const y = 20;
  console.log(x); // 輸出:10
  console.log(y); // 輸出:20
}

console.log(x); // ReferenceError: x is not defined
console.log(y); // ReferenceError: y is not defined

解釋:

  • x 和 y 在區塊內宣告,僅在該區塊內部可訪問。
  • 在區塊外部訪問 x 和 y 會拋出錯誤。

範例 2:暫時性死區

{
  console.log(z); // ReferenceError: Cannot access 'z' before initialization
  let z = 5;
}

解釋:

  • 在宣告變數 z 之前訪問它,會拋出 ReferenceError,因為它處於暫時性死區。

範例 3:在循環中的區塊作用域

for (let i = 0; i < 3; i++) {
  console.log(i); // 輸出:0, 1, 2
}

console.log(i); // ReferenceError: i is not defined

解釋:

  • let i = 0; 宣告的變數 i,作用域僅限於 for 迴圈的區塊內。
  • 在迴圈外部訪問 i 會拋出錯誤。

函式作用域與區塊作用域的差異

作用範圍

  • 函式作用域:變數的作用範圍限制在函式內部,對於 var 宣告的變數適用。
  • 區塊作用域:變數的作用範圍限制在區塊 {} 內部,對於 let 和 const 宣告的變數適用。

變數提升

  • 函式作用域(var):
    • 變數提升到作用域頂部,初始化為 undefined。
    • 可以在變數宣告之前訪問變數,但值為 undefined。
  • 區塊作用域(let、const):
    • 變數被提升但不初始化,處於暫時性死區。
    • 在變數宣告之前訪問變數會拋出 ReferenceError。

變數的重複宣告

  • var:允許在同一作用域內重複宣告變數,後面的宣告會覆蓋前面的。
  • let、const:不允許在同一作用域內重複宣告變數,否則會拋出 SyntaxError。

範例:

function example() {
  var a = 1;
  var a = 2; // 允許,a 的值被更新為 2
  console.log(a); // 輸出:2

  let b = 1;
  let b = 2; // SyntaxError: Identifier 'b' has already been declared
}

example();

最佳實踐

優先使用 let 和 const

  • 提升代碼安全性:避免變數提升和暫時性死區帶來的問題。
  • 提高可讀性:使變數的作用範圍更加清晰。

使用 const 儲存常量

  • 不可變性:const 宣告的變數不可重新賦值,適用於不會改變的值。
  • 預防意外修改:防止變數被重新賦值導致的錯誤。

避免使用 var

  • 防止作用域污染:var 沒有區塊作用域,可能導致變數在不應該的地方被修改。
  • 避免變數提升:var 的提升可能導致難以預測的行為。

明確劃分作用域

  • 利用區塊作用域:將相關的代碼組織在一起,限制變數的可見性。
  • 減少全域變數的使用:盡量將變數限制在需要的最小作用域內。

結語

理解 JavaScript 的函式作用域和區塊作用域,對於撰寫高品質的程式碼至關重要。

透過正確地使用 let、const 和 var,你可以:

  • 控制變數的生命週期:確保變數在需要的時候可用,避免不必要的內存佔用。
  • 提高代碼的可維護性:清晰的作用域結構讓程式碼更易於理解和修改。
  • 避免常見錯誤:如變數提升、作用域污染等問題。

希望本文能夠幫助你深入了解這兩種作用域的概念,並在未來的開發中靈活運用這些知識,寫出更健壯和可靠的 JavaScript 程式碼。


參考資料

  • MDN Web Docs – 變數作用域
  • JavaScript 深入系列 – 作用域與閉包
  • ES6 入門教程 – let 和 const 命令
目前還沒有留言,成為第一個留言的人吧!

發表留言

留言將在審核後顯示。

JavaScript

目錄

  • 什麼是作用域?
  • 函式作用域(Function Scope)
  • 定義
  • 特點
  • 範例
  • 變數提升帶來的問題
  • 區塊作用域(Block Scope)
  • 定義
  • 特點
  • 範例
  • 函式作用域與區塊作用域的差異
  • 作用範圍
  • 變數提升
  • 變數的重複宣告
  • 最佳實踐
  • 優先使用 let 和 const
  • 使用 const 儲存常量
  • 避免使用 var
  • 明確劃分作用域
  • 結語
  • 參考資料