作用域與作用域鏈

遠方是夢的故鄉發表於2020-11-01

1.什麼是作用域

作用域是在執行時程式碼中的某些特定部分中變數,函式和物件的可訪問性。換句話說,作用域決定了程式碼區塊中變數和其他資源的可見性。可能這兩句話並不好理解,我們先來看個例子:

function outFun2() {
    var inVariable = "內層變數2";
}

outFun2();//要先執行這個函式,否則根本不知道里面是啥

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

從上面的例子可以體會到作用域的概念,變數 inVariable 在全域性作用域沒有宣告,所以在全域性作用域下取值會報錯。我們可以這樣理解:作用域就是一個獨立的地盤,讓變數不會外洩、暴露出去。也就是說作用域最大的用處就是隔離變數,不同作用域下同名變數不會有衝突。

ES6 之前 JavaScript 沒有塊級作用域,只有全域性作用域和函式作用域。ES6 的到來,為我們提供了‘塊級作用域’,可通過新增命令 let 和 const 來體現。

2.塊級作用域可通過新增命令 let 和 const 宣告,所宣告的變數在指定塊的作用域外無法被訪問。塊級作用域在如下情況被建立:

在一個函式內部

在一個程式碼塊(由一對花括號包裹)內部

let 宣告的語法與 var 的語法一致。你基本上可以用 let 來代替 var 進行變數宣告,但會將變數的作用域限制在當前程式碼塊中。塊級作用域有以下幾個特點:

宣告變數不會提升到程式碼塊頂部

let/const 宣告並不會被提升到當前程式碼塊的頂部,因此你需要手動將 let/const 宣告放置到頂部,以便讓變數在整個程式碼塊內部可用。

function getValue(condition) {
if (condition) {
let value = “blue”;
return value;
} else {
// value 在此處不可用
return null;
}
// value 在此處不可用
}
禁止重複宣告
如果一個識別符號已經在程式碼塊內部被定義,那麼在此程式碼塊內使用同一個識別符號進行 let 宣告就會導致丟擲錯誤。例如:

var count = 30;
let count = 40; // Uncaught SyntaxError: Identifier 'count' has already been declared

在本例中, count 變數被宣告瞭兩次:一次使用 var ,另一次使用 let 。因為 let 不能在同一作用域內重複宣告一個已有識別符號,此處的 let 宣告就會丟擲錯誤。但如果在巢狀的作用域內使用 let 宣告一個同名的新變數,則不會丟擲錯誤。

var count = 30;
// 不會丟擲錯誤
if (condition) {
let count = 40;
// 其他程式碼
}

迴圈中的繫結塊作用域的妙用
開發者可能最希望實現 for 迴圈的塊級作用域了,因為可以把宣告的計數器變數限制在迴圈內,例如,以下程式碼在 JS 經常見到:

測試1
測試2
測試3

我們要實現這樣的一個需求: 點選某個按鈕, 提示"點選的是第 n 個按鈕",此處我們先不考慮事件代理,萬萬沒想到,點選任意一個按鈕,後臺都是彈出“第四個”,這是因為 i 是全域性變數,執行到點選事件時,此時 i 的值為 3。那該如何修改,最簡單的是用 let 宣告 i

 for (let i = 0; i < btns.length; i++) {
    btns[i].onclick = function () {
      console.log('第' + (i + 1) + '個')
    }
  }

3.什麼是作用域鏈

如果父級也沒呢?再一層一層向上尋找,直到找到全域性作用域還是沒找到,就宣佈放棄。這種一層一層的關係,就是 作用域鏈 。

3.什麼是作用域鏈

如果父級也沒呢?再一層一層向上尋找,直到找到全域性作用域還是沒找到,就宣佈放棄。這種一層一層的關係,就是 作用域鏈 。

var a = 100
function F1() {
    var b = 200
    function F2() {
        var c = 300
        console.log(a) // 自由變數,順作用域鏈向父作用域找
        console.log(b) // 自由變數,順作用域鏈向父作用域找
        console.log(c) // 本作用域的變數
    }
    F2()
}
F1()
var a = 100
function F1() {
    var b = 200
    function F2() {
        var c = 300
        console.log(a) // 自由變數,順作用域鏈向父作用域找
        console.log(b) // 自由變數,順作用域鏈向父作用域找
        console.log(c) // 本作用域的變數
    }
    F2()
}
F1()

內容轉載至部落格園-一粒一世界

相關文章