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