本文會用思惟導圖的形式列出本書該部分的知識點(剔除案例),構建知識脈絡。因爲是導讀,正文部分只會列舉部分的內容。本文適合未讀過此書的同窗參考,另外讀過此書的同窗,若是能純熟得答出文初的問題,那麼相信您對於這部分的內容能夠說是記憶深入了。編程
建議在閱讀前瞭解做者的平生,背景,核心貢獻及思想。相信會對理解本書以及後續的選書讀書會有所幫助。bash
豆瓣讀書編程語言
ReferenceError
異常類型 和 TypeError
異常類型。談談你對做用域的理解。(我的理解,求拍磚)函數
做用域收集而且維護由全部聲明的標識符組成的查詢,有本身很是嚴格的規則肯定當前執行代碼對標識符的訪問權限。性能
JavaScript 是一門編譯語言,在執行代碼前的編譯中,編譯器須要和做用域溝通是否存在某個變量來決定建立仍是忽略。優化
接着引擎須要爲變量賦值,它會經過 LHS查詢
或者 RHS查詢
查找變量,在當前做用域找不到時還要沿着做用域鏈一直往上往上找,若是在最外層的全局做用域也找不到,那麼拋出叫作 ReferenceError 的異常spa
這裏若是是使用 LHS查詢
當全局做用域也不存在查找的變量時會自動建立並返還給引擎。code
JavaScript
是一門編譯語言,可是它不像傳統語言那樣僅僅只經歷編譯的三個步驟,分詞/詞法分析,解析/語法分析,代碼生成。cdn
咱們的 JavaScript
引擎要複雜的多,JavaScript
會用盡各辦法(好比用JIT
)來保證性能最佳。而且咱們要記住的是任何 JavaScript
代碼片斷在執行前都要進行編譯,大部分狀況下編譯發生在代碼執行前的幾微秒(甚至更短)。對象
分詞/詞法分析:這個過程會將字符串分解成對編程語言來講有意義的詞法單元(代碼塊)
var a = zhengyang;
複製代碼
以上代碼會被分解成 var、a、=、; 空格是否會被當成語法單元取決於它是否在此處具備意義。
分詞和詞法分析實際上是一件事,詞在這裏指的是帶有某種歸類的字符串,詞經過詞法來劃分,分詞是目的,詞法分析是手段。
解析/語法分析:這個過程會將詞法單元流轉化成一個由元素逐級嵌套所組成的表明程序語法結構的樹,這個樹叫作抽象語法樹(Abstract Syntax Tree
,AST)。
var a = zhengyang;
複製代碼
通過分詞/詞法分析,咱們把劃分好的代碼塊組成抽象語法樹,它有一個 VariableDeclaration
(變量聲明) 的頂級節點,下面是一個 Identitier
(值爲a)的子節點和一個叫作 AssignmentExpression
(賦值表達式)的子節點,AssignmentExpression
有一個叫作 NumericLiteral
(數值文字)的值爲 2 的子節點。
代碼生成:將 AST
轉化爲課執行代碼的過程被稱爲代碼生成。
簡單來講就是將 var a = 2
的 AST
轉化爲一組機器指令來創造一個叫作 a 的變量,並將一個值存儲在 a 中。
引擎:從頭至尾負責整個 JavaScript
的編譯及執行過程。
編譯器:引擎的同事負責語法分析及代碼生成等髒活累活。
做用域:引擎的另外一位同事,負責收集而且維護全部聲明的標識符組成的一些列諮詢。它由一套很是嚴格個規則,肯定當前執行的代碼對這些標識符的訪問權限。
三位一體工做流:
var a = zhengyang
複製代碼
var a
,編譯器會諮詢做用域是否已經存在該名稱的變量存在於同一個做用域集合中。是,就忽略 var a
繼續編譯;不然就會要求在當前做用域集合中生命一個新的變量,命名爲 aa = 2
這個賦值操做。引擎在運行時會先諮詢做用域,當前的做用域集合中是否存在一個叫作a的變量。是,就會使用這個變量;否,引擎就會繼續查找該變量。LHS查詢
與 RHS查詢
:簡單來講 LHS
查詢就是當變量出如今賦值操做的左側時進行的查詢, RHS查詢
就是變量出如今賦值操做的右側時進行的查詢。要注意,查找只會在當前做用域進行。console.log(a)
複製代碼
以上代碼就是 RHS查詢
,咱們能夠看到變量 a 出如今右側。
a = 2
複製代碼
以上代碼就是 LHS查詢
, 變量 a 出如今左側。 6. 看一個具體例子
function foo(a) {
console.log(a);//2
}
foo (2)
複製代碼
以上代碼首先進行的聲明 foo 函數,變量在右因此使 RHS查詢
而後是隱式的 a = 2
這裏採用 RHS查詢
,變量在左因此使用 LHS查詢
console.log
console是內置對象,找 log
變量在右使用 RHS查詢
console.log(a)
同上變量在右使用 RHS查詢
做用域是根據名稱查找變臉的一套規則,當一個塊或函數嵌套在另外一個塊或函數中時就發生了做用域的嵌套。在當前做用域沒法找到某個變量時,引擎就會在外層嵌套的做用域中繼續查找,直到找到該變量爲止。
function foo(a){
console.log(a + b)
}
var b = 2
foo(2); //4
複製代碼
上面的代碼中 console.log(a + b)
咱們在函數做用域中找不到 b 只能在上層的全局做用域中找
遍歷嵌套做用域做用域鏈的規則:引擎從當前的執行做用於開始查找變量,若是找不到就去上級繼續查找。當抵達最外層的全局做用域時,若是尚未找到,那麼查找就會中止。
如上圖的一條做用域鏈,咱們在當前做用域要找到 a 、b、c 當前做用域沒有就去外層做用域找在,找到了 b ,c沒找到繼續往外找,而後在全局做用域找到了 c 若是到此時尚未找到,那麼查找就會中止。function foo(a) {
console.log( a + b);
b = a;
}
複製代碼
以上代碼會報 ReferenceError
的異常,由於咱們經過 RHS 查詢
在全部的嵌套做用域中都找不到 b。
相比之下若是是用 LHS查詢
非嚴格模式下,若是在全局做用於中也找不到就會幫你建立一個具備該名稱的變量,而且返還給引擎。
嚴格模式禁止自動或隱式地建立全局變量。所以在嚴格模式中 LHS查詢
失敗時並不會建立並返回一個全局變量,而是會拋出 ReferenceError
異常。
TypeError
若是經過 RHS查詢
找到了一個變量,可是你嘗試對這個變量的值進行不合理的操做,好比對一個非函數類型進行函數調用那麼就會拋出 TypeError
異常。
var a = 'zhengyang'
複製代碼
a = 'zhengyang'
這個賦值操做。LHS查詢
或者 RHS查詢
在當前做用域查找變量。若是找到了引擎就會使用這個變量將 'zhengyang' 這個值賦給它。ReferenceError
異常。LHS查詢
,當最外層的全局做用域也不存在要查找的變量時會自動建立而且返回該變量給引擎,嚴格模式下則不可,由於嚴格模式禁止自動或隱式建立全局變量。