圖解詞法做用域與做用域鏈

做用域

做用域是指程序源代碼中定義變量的區域。

做用域規定了如何查找變量,也就是肯定當前執行代碼對變量的訪問權限。

JavaScript 採用詞法做用域(lexical scoping),也就是靜態做用域。

想了解更多關於做用域的問題推薦閱讀《你不知道的JavaScript上卷》第一章(或第一部分),
從編譯原理的角度說明什麼是做用域。歸納的說做用域就是一套設計良好的規則來存儲變量,而且以後能夠方便地找到這些變量。
複製代碼

詞法做用域

在你不知道的javascript上卷中是這樣定義的:詞法做用域就是定義在詞法階段的做用域。換句話說,詞法做用域是由你在寫代碼時將變量和塊做用域寫在哪裏來決定的,所以當詞法分析器處理代碼時會保持做用域不變(大部分狀況下是這樣的)。javascript

在JS中詞法做用域的規則:java

  • 函數容許訪問函數外部的數據
  • 整個代碼結構中只有函數能夠限定做用域
  • 做用規則首先使用提高規則分析
  • 若是當前做用域中有了名字了,就不考慮外面的名字

例1bash

var a = 2;
function foo() {
  var a = 3;
  console.log(a); // 3
}
foo();
複製代碼

例2函數

function foo() {
  console.log(a); // 2
}
function bar() {
  var a = 3;
  foo();
}
var a = 2;
bar();
複製代碼

做用域鏈

只有函數才能製造做用域結構,那麼只要是代碼,至少有一個做用域,即全局做用域。ui

凡是代碼中有函數,那麼這個函數就構成另外一個做用域。若是函數中還有函數,那麼在這個做用域中就又能夠誕生一個做用域,那麼將這樣的全部做用域列出來,能夠有一個結構:函數內指向函數外的鏈式結構。spa

以上面例2:設計

function foo() {
  console.log(a); // 2
}
function bar() {
  var a = 3;
  foo();
}
var a = 2;
bar();
複製代碼
  • 全局做用域,有三個標識符:foo、bar、a
  • bar 所建立的做用域,其中有一個標識符:a

做用域是由代碼寫在哪裏決定的,而且是逐級包含的。code

咱們用級鏈來表示一下以上代碼塊:cdn

從圖中咱們能夠看到:函數foo和bar以及變量 a=2, 在1級鏈,而bar下又能夠展開2級鏈,2級鏈上有a=3。程序bar()調用進入中間2級鏈,而bar中又調用了foo函數,此時程序進入foo的做用域鏈,按照向上查找的原則,程序會從這一條鏈向上查找,首先2級鏈沒有a,向上到達1級鏈,恰好1級鏈上有a=2,因此就直接使用2,程序最後的結果就是打印2。

因此不管函數在哪裏被調用,也不管它如何被調用,它的詞法做用域都只由函數被聲明時所處的位置決定。blog

實踐

var scope = "global scope";
function checkscope(){
  var scope = "local scope";
  function f(){
    return scope;
  }
  return f();
}
checkscope();
複製代碼

相關文章
相關標籤/搜索