那些年不懂的JS - Scope 範疇


Posted by Andy Tsai on 2020-04-19

Scope是什麼?

Scope就是變數的有效範圍(可以被取用的範圍),一旦超出範圍就無法存取,
可以分為幾種-全域範疇、函式範疇、區塊範疇

Global Scope 全域範疇:

全域範疇指的是最外層的範疇,精準來說是瀏覽器中BOM的window物件,

想了解更多瀏覽器知識,可以看看kuro大大的文章
重新認識 JavaScript: Day 11 前端工程師的主戰場:瀏覽器裡的 JavaScript

我們在全域範疇設的變數(全域變數),都會成為全域物件的屬性
所以我們也可以用 window. 去取得我們得變數

var a = 1; // 全域變數
console.log(window.a) // 1

全域範疇的有效範圍是全部,在代碼中的任何地方都可以取用。

Function Scope 函式範疇

每個函式都會有自己的範疇,有效範圍只在函式內部,外層無法直接訪問函式中的範疇,
並且函式結束後,裡面的變數就無法取得了。

function foo() {
    var a =3
    function test(){
        console.log(a) // 3 在有效範圍中,順利取得
    }
    console.log(a) // 3 在有效範圍中,順利取得
    test()
}
foo()
console.log(a) // a is not defined 超出範圍,取不到function內的變數

另外要注意的是,如果沒有用var宣告,就算在函式內也會被視為全域變數,
盡量不要這樣做,因為污染全域不是一個好主意。

Scope Chain 範圍鏈

插撥一個觀念,大家會發現上面的代碼中foo()裡面的test(),也取得到外層的a變數,
這其實就是Scope Chain(範圍鏈)的概念,當它在範疇內找不到變數時,會從自己的層級開始,一層層往上找,直到找到第一個符合的為止。

Block Scope 區塊範疇

在ES6以前,並沒有區塊範疇的概念,我們只能以函式為區分,
而從ES6開始,引入了Let、Const關鍵字,它們以區塊{}當範疇,如此一來我們就可以利用區塊範疇寫出更嚴謹,更好維護的代碼。

{
  var a = 1;
  let b = 10;
}
console.log(a); // 1
console.log(b); // b is not defined

可以看到上面代碼中,外層的console.log(b)是取不到的,因為b用let宣告,所以它只在{}中有效,超出範圍當然就取不到了

區塊範疇的好處不少,它能讓我們更靈活地管理變數,更簡潔明確的邏輯劃分,並把資訊的隱藏從函式層級進階到區塊層級,也更符合最小權限原則

舉個例子,這是一個看似平凡的for迴圈

for(var i=0; i<10; i++{
    console.log(i)
}

但這裡的var i是全域變數,可是我們只會在for迴圈裡中使用這個i,那麼為何要污染全域範疇呢?
而且還會造成潛在的問題,如果i在其他地方被誤用? 如果某處又宣告了i造成命名衝突?

所以更好的做法是把它改成let,鎖在{}中。

Let與迴圈

如果我們在for迴圈使用let宣告,它除了會將變數鎖在for的{}之外,還會重新繫結到迴圈的每次迭代,確保每次的變數都是前一次迭代的結果。

來看一個面試中常見的題目,以下代碼的執行結果為?

for(var i = 0; i < 5; i++) {
  setTimeout(function() {
     console.log(i); 
  }, 0);
};

很多新手會答01234(我以前也是),但這是錯誤的,正解是 55555

原因是,var會讓i成為一個全域變數,而setTimeout會在for跑完之後才執行,所以當setTimeout實際執行時,這時i已經是5了

可能有人會問,為什麼setTimeout在for跑完之後才執行?
這牽扯到Event Queue的觀念,如果不了解,可以看我上一篇文章
理解Javascript中的Event Loop

要讓它正確顯示01234,很簡單,用let來宣告i就可以了,同時我們也知道它有重新繫結的特性,所以可以確保每次迭代中的i都會是前一次迭代的結果。

Reference:
You Don't Know JS: Scope & Closures


#javascript #scope #範疇 #w3HexSchool







Related Posts

The introduction and difference between class component and function component in React

The introduction and difference between class component and function component in React

迴圈 for ..in

迴圈 for ..in

Day 122

Day 122


Comments