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