You-Dont-Know-JS - 詞法做用域

原文: 原文1 | 原文2javascript

Lexical Scope - 詞法做用域java

做用域有兩種常見的模型,一種叫作 詞法做用域 Lexical Scope,一種叫作動態做用域 Dynamic Scope。其中詞法做用域更常見,被大多數語言採用,包括javascript。git

詞法分析

詞法分析過程Lex-time,是指系統講源碼字符串解讀成有含義的token的過程。詞法做用域就是說在詞法分析過程當中指派的做用域,詞法做用域在詞法解析過程當中就已經定死了。github

依然有一些手段能在詞法解析以後改變詞法做用域,但這些作法並不推薦。使用關鍵詞eval, with,會產生性能問題。瀏覽器

考慮以下代碼:
fig2.png函數

  • 氣泡(做用域) 1 :即全局做用域,包含變量foo
  • 氣泡(做用域) 2 :foo的做用域,包含變量a,bar,b
  • 氣泡(做用域) 3 :bar的做用域,包含變量c

bar 做用域裏完整的包含了foo 的做用域, 由於bar 是在foo中定義的,產生嵌套做用域。值得注意的是,一個函數做用域只有可能存在於一個父級做用域中,不會同時存在兩個父級做用域。性能

過程:this

語句console.log尋找變量a,b,c 其中c在本身的做用域中找到,a,b在本身的做用域中找不到,因而向上級做用域中查找,在foo的做用域中找到,而且調用。做用域向上查找的過程當中,匹配第一次查找到的變量,也就是說若是foo的做用域中也定義了c,但bar函數只調用本身做用域裏的c。spa

做用域的查找一直會找到全局做用域的全局對象,好比瀏覽器中的window,你能夠定義window.a來確保變量a能夠被獲取。code

詞法做用域向上查找只查找第一級變量,好比變量foo.bar.baz, 查找的是對象foo,查找到了再從對象裏獲取bar以及baz,查找自己與bar,baz無關。

動態做用域 Dynamic Scope

動態做用域,javascript並沒有採用,可是與js的 this機制很是類似,看以下代碼:
動態做用域是在代碼運行時定義的,而非代碼解析時。

function foo() {
    console.log( a ); 
}

function bar() {
    var a = 3;
    foo();
}

var a = 2;

bar();

bar調用,bar裏面foo被調用,foo函數須要查找變量a,因爲javascript採用詞法做用域,foo被解析的時候是在全局做用域,因此a是全局做用域中的2,而非bar裏面的a。假設js採用的是動態做用域,foo是在bar中被調用的,因此a查找到了bar做用域裏的3。

做爲對照,動態做用域不關心它自己是怎樣在哪裏聲明的,只關心它在哪裏調用的,動態做用域的域鏈基於調用棧,而不是代碼中的嵌套關係。

相反,詞法做用域關心的是函數在哪裏聲明的,動態做用域的概念和js中的this相同,this也關心函數在哪裏調用的。

相關文章
相關標籤/搜索