Javascript 的作用域 (Scope) 与作用域链 (Scope Chain) 是什么?

2022年10月11日

💎 加入 E+ 成長計畫 與超過 500+ 位軟體工程師一同在社群中成長,並且獲得更多的軟體工程學習資源

什么是作用域 (Scope) ?

作用域这个概念,其实就像是范围的概念。在 JavaScript 里,「有作用」就是指可以被用上,可以被找到。所以,一个值(value)或者一个表达式(expression)可以被使用和找到的范围,我们就称之为作用域。

更正式一点来讲,根据MDN 的解释,作用域指的是当前正在执行的上下文,也就是程式目前所处的情境。在这个情境内,我们可以轻松地存取各种值(value)或表达式(expression)。换句话说,如果有一个变数或表达式并不在这个情境中,那么就不能轻易地使用它。

JavaScript 的作用域分为三种:

  • 全域(Global Scope):当 JavaScript 代码被执行一开始时,就会创建一个全域执行环境,被定义在函式或块级以外的变数,就会属于全局作用域,这些变数也被称之为全域变数(Global variable),在代码中的任何地方都能被使用到。以下例子的 a 值就是在全局作用域的全域变数。

    var a = "全局作用域";
    
    function call() {
      console.log(a); // 全局作用域
      a = "哈啰全局作用域~~";
    }
    call();
    console.log(a); // 哈啰全局作用域~~
    
  • 函式作用域 (Function Scope):由函式所创建的作用域

    function scope() {
      let a = "函式作用域";
      console.log(a); // 函式作用域
    }
    // a 在此处不可用,因为 a 是函式作用域
    
  • 块级作用域 (Block Scope):ES6 之后才出现,被定义在一个块级中,如下面例子,在 if else 判断式中,就属于块级作用域。要注意的是,只有 letconst 定义的变数会属于块级作用域,如果是 var 定义的变数会是只有函式作用域。

    function checkScope() {
      if (true) {
        let a = "块级作用域";
        var b = "函式作用域";
      } else {
        // a 变数属于 if 判断式中的块级作用域,在此处不可用
        // b 变数属于 check 函式的作用域,在此处可用
        console.log(b); // 函式作用域
      }
      // a 在此处不可用,b 在此处可用
    }
    // a,b 在此处不可用
    

什么是作用域链 (Scope Chain)?

当 JavaScript 使用每一个变数的时候,会先尝试在当前作用域中寻找该变数,若在当前的作用域找不到该变数,会一直往父层作用域寻找,直到全局作用域还是没找到,就会直接报错,这一层一层的关系,就是作用域链。让我们透过以下代码来了解:

let a = 100;
function find() {
  // 在 find 函式作用域中没有变数 a,于是透过作用域链往父层寻找,
  // 在这边的父层是全域,也就找到了 a 变数
  console.log(a); // 100
}
find();
🧵 如果你想收到最即時的內容更新,可以在 FacebookInstagram 上追蹤我們