摘要:的抽象語法樹中可能會有一個叫作的頂級節點,接下來是一個叫作它的值是的子節點,以及一個叫作的子節點。值得注意的是,是非常重要的異常類型。嚴格模式下,未聲明的和倆者行為相同,都會是。
你不知道的JS(上卷)筆記
你不知道的 JavaScript
JavaScript 既是一門充滿吸引力、簡單易用的語言,又是一門具有許多復雜微妙技術的語言,即使是經驗豐富的 JavaScript 開發者,如果沒有認真學習的話也無法真正理解它們.
上卷包括倆節:
作用域和閉包
this 和對象原型
作用域和閉包希望 Kyle 對 JavaScript 工作原理每一個細節的批判性思 考會滲透到你的思考過程和日常工作中。知其然,也要知其所以然。
作用域是什么? 倆個事實能夠儲存變量值并能在之后對這個值進行訪問和修改(幾乎所有編程語言最基本的功能之一)
若沒有了狀態這個概念,程序雖然也能夠執行一些簡單的任務,但它會受到高度限制,做 不到非常有趣。(正是這種儲存和訪問變量的值的能力將狀態帶給了程序)
提出問題變量存在哪?
程序需要時如何找到他們?
需要一套規則來處理變量的問題,解決上述問題需要一套設計良好的規則來存儲變量,并且之后可以方便的找到變量,這套規則被稱為 作用域。
新的問題作用域規則在哪里?
怎么樣設置這些規則?
編譯原理JavaScript是一門編譯語言。
不是提前編譯
編譯結果也不能在分布式系統中移植
傳統語言的編譯流程:
分詞/詞法分析(Tokenizing/Lexing)
這個過程會將由字符組成的字符串分解成(對編程語言來說)有意義的代碼塊,這些代 碼塊被稱為詞法單元(token)。例如,考慮程序var a = 2;。這段程序通常會被分解成 為下面這些詞法單元:var、a、=、2 、;。空格是否會被當作詞法單元,取決于空格在 這門語言中是否具有意義。。
分詞(tokenizing)和詞法分析(Lexing)之間的區別主要差異在于詞法單元的識別是通過有狀態還是無狀態的方式進行的。簡 單來說,如果詞法單元生成器在判斷 a 是一個獨立的詞法單元還是其他詞法單元的一部分時,調用的是有狀態的解析規則,那么這個過程就被稱為詞法分析。
解析/語法分析(Parsing)
這個過程是將詞法單元流(數組)轉換成一個由元素逐級嵌套所組成的代表了程序語法 結構的樹。這個樹被稱為“抽象語法樹”(Abstract Syntax Tree,AST)。var a = 2; 的抽象語法樹中可能會有一個叫作 VariableDeclaration 的頂級節點,接下 來是一個叫作 Identifier(它的值是 a)的子節點,以及一個叫作 AssignmentExpression 的子節點。AssignmentExpression 節點有一個叫作 NumericLiteral(它的值是 2)的子節點。
代碼生成
將 AST 轉換為可執行代碼的過程稱被稱為代碼生成。這個過程與語言、目標平臺等息 息相關。拋開具體細節,簡單來說就是有某種方法可以將 var a = 2; 的 AST 轉化為一組機器指 令,用來創建一個叫作 a 的變量(包括分配內存等),并將一個值儲存在 a 中。
JavaScript 引擎不會有大量的(像其他語言編譯器那么多的)時間用來進行優化,因 為與其他語言不同,JavaScript 的編譯過程不是發生在構建之前的。
任何 JavaScript 代碼片段在執行前都要進行編譯(通常就在執行前)。因此, JavaScript 編譯器首先會對 var a = 2; 這段程序進行編譯,然后做好執行它的準備,并且 通常馬上就會執行它。
理解作用域對話形式模擬作用域的工作方式
參與到對程序 var a = 2; 進行處理的過程中的演員們
引擎
從頭到尾負責整個 JavaScript 程序的編譯及執行過程。
編譯器
負責語法分析及代碼生成等。
作用域
負責收集并維護由所有聲明的標識符(變量)組成的一系列查 詢,并實施一套非常嚴格的規則,確定當前執行的代碼對這些標識符的訪問權限。
編譯器首先會將這段程序分解成詞法單元,然后將詞法單元解析成一個樹結構。但是當編 譯器開始進行代碼生成時,它對這段程序的處理方式會和預期的有所不同。
可以合理地假設編譯器所產生的代碼能夠用下面的偽代碼進行概括:“為一個變量分配內 存,將其命名為 a,然后將值 2 保存進這個變量。”然而,這并不完全正確。
事實上編譯器會進行如下處理。
遇到 var a,編譯器會詢問作用域是否已經有一個該名稱的變量存在于同一個作用域的 集合中。如果是,編譯器會忽略該聲明,繼續進行編譯;否則它會要求作用域在當前作 用域的集合中聲明一個新的變量,并命名為 a。
接下來編譯器會為引擎生成運行時所需的代碼,這些代碼被用來處理 a = 2 這個賦值 操作。引擎運行時會首先詢問作用域,在當前的作用域集合中是否存在一個叫作 a 的 變量。如果是,引擎就會使用這個變量;如果否,引擎會繼續查找該變量(查看 1.3 節)。
總結:變量的賦值操作會執行兩個動作,首先編譯器會在當前作用域中聲明一個變量(如 果之前沒有聲明過),然后在運行時引擎會在作用域中查找該變量,如果能夠找到就會對 它賦值。
LHS
RHS
異常為什么區分 LHS 和 RHS 是一件重要的事情?
因為在變量還沒有聲明(在任何作用域中都無法找到該變量)的情況下,這兩種查詢的行 為是不一樣的。
如果 RHS 查詢在所有嵌套的作用域中遍尋不到所需的變量,引擎就會拋出 ReferenceError 異常。值得注意的是,ReferenceError 是非常重要的異常類型。
相較之下,當引擎執行 LHS 查詢時,如果在頂層(全局作用域)中也無法找到目標變量,
全局作用域中就會創建一個具有該名稱的變量,并將其返還給引擎,前提是程序運行在非 “嚴格模式”下。
嚴格模式下,未聲明的RHS和LHS倆者行為相同,都會是 ReferenceError。
ReferenceError 同作用域判別失敗相關,而 TypeError 則代表作用域判別成功了,但是對 結果的操作是非法或不合理的。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/108972.html
摘要:如果提升改變了代碼執行的順序,會造成非常嚴重的破壞。聲明本身會被提升,而包括函數表達式的賦值在內的賦值操作并不會提升。要注意避免重復聲明,特別是當普通的聲明和函數聲明混合在一起的時候,否則會引起很多危險的問題 你不知道的JS(上卷)筆記 你不知道的 JavaScript JavaScript 既是一門充滿吸引力、簡單易用的語言,又是一門具有許多復雜微妙技術的語言,即使是經驗豐富的 Ja...
摘要:詞法作用域的查找規則是閉包的一部分。因此的確同閉包息息相關,即使本身并不會真的使用閉包。而上面的創建一個閉包,本質上這是將一個塊轉換成一個可以被關閉的作用域。結合塊級作用域與閉包模塊這個模式在中被稱為模塊。 你不知道的JS(上卷)筆記 你不知道的 JavaScript JavaScript 既是一門充滿吸引力、簡單易用的語言,又是一門具有許多復雜微妙技術的語言,即使是經驗豐富的 Jav...
摘要:如果是聲明中的第一個詞,那么就是一個函數聲明,否則就是一個函數表達式。給函數表達式指定一個函數名可以有效的解決以上問題。始終給函數表達式命名是一個最佳實踐。也有開發者干脆關閉了靜態檢查工具對重復變量名的檢查。 你不知道的JS(上卷)筆記 你不知道的 JavaScript JavaScript 既是一門充滿吸引力、簡單易用的語言,又是一門具有許多復雜微妙技術的語言,即使是經驗豐富的 Ja...
摘要:詞法作用域定義在詞法階段的作用域由你在寫代碼時將變量和塊作用域寫在哪來決定的,因此當詞法分析器處理代碼時會保持作用域不變。欺騙詞法作用域在詞法分析器處理過后依然可以修改作用域。 你不知道的JS(上卷)筆記 你不知道的 JavaScript JavaScript 既是一門充滿吸引力、簡單易用的語言,又是一門具有許多復雜微妙技術的語言,即使是經驗豐富的 JavaScript 開發者,如果沒...
摘要:種原始類型對象屬性種原始類型中種原始類型為,,,,發現除外的其他種基本類型均可以用來識別因為會得到,所以直接用來檢測對象的對象包括內置對象,,等和自定義對象。其他檢測方法,都各有缺陷,不能精確。屬性檢測屬性是否在實例對象中應該用。 本篇介紹一下如何檢測JavaScript各種類型。 ? 5種原始類型? 對象? Function? Array? 屬性 5種原...
閱讀 1271·2021-11-15 18:14
閱讀 3127·2021-08-25 09:38
閱讀 2663·2019-08-30 10:55
閱讀 2673·2019-08-29 16:39
閱讀 1305·2019-08-29 15:07
閱讀 2446·2019-08-29 14:14
閱讀 810·2019-08-29 12:36
閱讀 909·2019-08-29 11:21