摘要:無論你使用的是解釋型語言還是編譯型語言,都有一個(gè)共同的部分將源代碼作為純文本解析為抽象語法樹的數(shù)據(jù)結(jié)構(gòu)。和抽象語法樹相對(duì)的是具體語法樹,通常稱作分析樹。這是引入字節(jié)碼緩存的原因。
這是專門探索 JavaScript 及其所構(gòu)建的組件的系列文章的第 14 篇。
想閱讀更多優(yōu)質(zhì)文章請(qǐng)猛戳GitHub博客,一年百來篇優(yōu)質(zhì)文章等著你!
如果你錯(cuò)過了前面的章節(jié),可以在這里找到它們:
JavaScript 是如何工作的:引擎,運(yùn)行時(shí)和調(diào)用堆棧的概述!
JavaScript 是如何工作的:深入V8引擎&編寫優(yōu)化代碼的5個(gè)技巧!
JavaScript 是如何工作的:內(nèi)存管理+如何處理4個(gè)常見的內(nèi)存泄漏 !
JavaScript 是如何工作的:事件循環(huán)和異步編程的崛起+ 5種使用 async/await 更好地編碼方式!
JavaScript 是如何工作的:深入探索 websocket 和HTTP/2與SSE +如何選擇正確的路徑!
JavaScript 是如何工作的:與 WebAssembly比較 及其使用場(chǎng)景 !
JavaScript 是如何工作的:Web Workers的構(gòu)建塊+ 5個(gè)使用他們的場(chǎng)景!
JavaScript 是如何工作的:Service Worker 的生命周期及使用場(chǎng)景!
JavaScript 是如何工作的:Web 推送通知的機(jī)制!
JavaScript是如何工作的:使用 MutationObserver 跟蹤 DOM 的變化!
JavaScript是如何工作的:渲染引擎和優(yōu)化其性能的技巧!
JavaScript是如何工作的:深入網(wǎng)絡(luò)層 + 如何優(yōu)化性能和安全!
JavaScript是如何工作的:CSS 和 JS 動(dòng)畫底層原理及如何優(yōu)化它們的性能!
概述我們都知道運(yùn)行一大段 JavaScript 代碼性能會(huì)變得很糟糕。這段代碼不僅需要通過網(wǎng)絡(luò)傳輸,而且還需要解析、編譯成字節(jié)碼,最后執(zhí)行。在之前的文章中,我們討論了 JS 引擎、運(yùn)行時(shí)和調(diào)用堆棧等,以及主要由谷歌 Chrome 和 NodeJS 使用的V8引擎。它們?cè)谡麄€(gè) JavaScript 執(zhí)行過程中都發(fā)揮著至關(guān)重要的作用。這篇說的抽象語法樹同樣重要:在這我們將了解大多數(shù) JavaScript 引擎如何將文本解析為對(duì)機(jī)器有意義的內(nèi)容,轉(zhuǎn)換之后發(fā)生的事情以及做為 Web 開發(fā)者如何利用這一知識(shí)。
編程語言原理那么,首先讓我們回顧一下編程語言原理。不管你使用什么編程語言,你需要一些軟件來處理源代碼以便讓計(jì)算機(jī)能夠理解。該軟件可以是解釋器,也可以是編譯器。無論你使用的是解釋型語言(JavaScript、Python、Ruby)還是編譯型語言(c#、Java、Rust),都有一個(gè)共同的部分:將源代碼作為純文本解析為 抽象語法樹(abstract syntax tree, AST) 的數(shù)據(jù)結(jié)構(gòu)。
AST 不僅以結(jié)構(gòu)化的方式顯示源代碼,而且在語義分析中扮演著重要角色。在語義分析中,編譯器驗(yàn)證程序和語言元素的語法使用是否正確。之后,使用 AST 來生成實(shí)際的字節(jié)碼或者機(jī)器碼。
抽象語法樹(abstract syntax tree 或者縮寫為 AST),或者語法樹(syntax tree),是源代碼的抽象語法結(jié)構(gòu)的樹狀表現(xiàn)形式,這里特指編程語言的源代碼。和抽象語法樹相對(duì)的是具體語法樹(concrete syntaxtree),通常稱作分析樹(parse tree)。一般的,在源代碼的翻譯和編譯過程中,語法分析器創(chuàng)建出分析樹。一旦 AST 被創(chuàng)建出來,在后續(xù)的處理過程中,比如語義分析階段,會(huì)添加一些信息。AST 程序
AST 不僅僅是用于語言解釋器和編譯器,在計(jì)算機(jī)世界中,它們還有多種應(yīng)用。使用它們最常見的方法之一是進(jìn)行靜態(tài)代碼分析。靜態(tài)分析器不執(zhí)行輸入的代碼,但是,他們?nèi)匀恍枰斫獯a的結(jié)構(gòu)。
例如,你可能想要實(shí)現(xiàn)一個(gè)工具,該工具可以找到公共代碼結(jié)構(gòu),以便你可以重構(gòu)它們以減少重復(fù)。你可能會(huì)通過使用字符串比較來實(shí)現(xiàn)這一點(diǎn),但這個(gè)會(huì)相當(dāng)簡(jiǎn)單且有局限性。
當(dāng)然,如果你對(duì)實(shí)現(xiàn)這樣的工具感興趣,你不需要編寫自己的解析器。有許多與 Ecmascript規(guī)范完全兼容的開源項(xiàng)目。Esprima 和 Acorn 即是黃金搭檔,還有許多工具可以幫助解析器生成輸出,即 ASTs ,ASTs 被廣泛應(yīng)用于代碼轉(zhuǎn)換。
例如,你可能希望實(shí)現(xiàn)一個(gè)將 Python 代碼轉(zhuǎn)換為J avaScript 的轉(zhuǎn)換器?;舅枷胧鞘褂肞ython 轉(zhuǎn)換器生成 AST,然后使用 AST 生成JavaScript代碼。
你可能會(huì)覺得難以置信,事實(shí)是 ASTs 只是部分語言的不同表示法。在解析之前,它被表示為遵循一些規(guī)則的文本,這些規(guī)則構(gòu)成了一種語言。在解析之后,它被表示為一個(gè)樹結(jié)構(gòu),其中包含與輸入文本完全相同的信息。因此,也可以進(jìn)行反向解析然后回到文本。
JavaScript 解析讓我們看看 AST 是如何構(gòu)建的。我們用一個(gè)簡(jiǎn)單的 JavaScript 函數(shù)作為例子:
function foo(x) { if (x > 10) { var a = 2; return a * x; } return x + 10; }
解析器會(huì)產(chǎn)生如下的 AST:
注意,為了觀看方便,這里是解析器將生成的結(jié)果的簡(jiǎn)化版本。實(shí)際的 AST 要復(fù)雜得多。然而,這里的目的是為了運(yùn)行源碼之前的第一個(gè)步驟前。如果人想查看實(shí)際的 AST 是什么樣子,可以訪問 AST Explorer。它是一個(gè)在線工具,你以在其中輸入一些 JavaScript 并輸出對(duì)應(yīng)的 AST。
你可能會(huì)問,為什么需要知道 JavaScript解析器工作原理,畢竟這是瀏覽器工作,你想法是部分正確。下圖展示了 JavaScript 執(zhí)行過程中不同階段的耗時(shí)。仔細(xì)瞅瞅,你或許會(huì)發(fā)現(xiàn)一些有趣的東西。
發(fā)現(xiàn)沒? 通常情況下,瀏覽器解析 JavaScript 大約需占總執(zhí)行時(shí)間的 15% 到 20%。我沒有具體統(tǒng)計(jì)過這些數(shù)值。這些是來自真實(shí)應(yīng)用程序和以某種方式使用 JavaScript 的網(wǎng)站的統(tǒng)計(jì)數(shù)據(jù)。也許 15% 看起來不是很多,但相信我,這是很多。
一個(gè)典型的單頁程序加載 0.4 mb 左右的 JavaScript,瀏覽器需要大約 370ms 來解析它。也許你會(huì)又說,這也不是很多嘛,本身花費(fèi)的時(shí)間并不多。但請(qǐng)記住,這只是將 JavaScript 代碼解析為 AST 所需要的時(shí)間。這并不包括運(yùn)行本身的時(shí)間,也不包括在頁面加載 ,如 CSS 和 HTML 渲染過程的耗時(shí)。這些還只涉及桌面,移動(dòng)瀏覽器的情況會(huì)更加復(fù)雜,在手機(jī)上花在解析上的時(shí)間通常是桌面瀏覽器的 2 到 5 倍。
上圖顯示了 1MB JavaScript 包在不同類的移動(dòng)和桌面瀏覽器解析時(shí)間。
更重要的是,為了獲得更多類原生的用戶體驗(yàn)而把越來越多的業(yè)務(wù)邏輯堆積在前端,Web 應(yīng)用程序正變得越來越復(fù)雜。你可以輕易地想到網(wǎng)絡(luò)應(yīng)用受到的性能影響。只需打開瀏覽器開發(fā)工具,然后使用該工具來解析、編譯和瀏覽器中發(fā)生的所有其他事情上所消耗的時(shí)間。
不幸的是,移動(dòng)瀏覽器上沒有開發(fā)者工具。不過不用擔(dān)心,這并不意味著你對(duì)此無能為力。因?yàn)橛?DeviceTiming 工具,它可以用來幫助檢測(cè)受控環(huán)境中腳本的解析和運(yùn)行時(shí)間。它通過插入代碼來封裝本地代碼,這樣每次從不同的設(shè)備訪問頁面時(shí),就可以在本地測(cè)量解析和運(yùn)行時(shí)間。
好事就是 JavaScript 引擎做了很多工作來避免冗余的工作,并得到了更好的優(yōu)化,以下為主流瀏覽器使用的技術(shù)。
例如,V8 實(shí)現(xiàn)腳本流(script streaming)和代碼緩存技術(shù)。腳本流即腳本一旦開始下載,async 和 deferred的 腳本就會(huì)在多帶帶的線程上解析。這意味著在下載腳本完成后幾乎立即完成解析,這會(huì)提升 10% 的頁面加載速度。
每次訪問頁面時(shí),JavaScript 代碼通常編譯為字節(jié)碼。 然而,一旦用戶訪問另一頁面,該字節(jié)碼就被丟棄。 發(fā)生這種情況是因?yàn)榫幾g后的代碼很大程度上依賴于編譯時(shí)機(jī)器的狀態(tài)和上下文。 這是 Chrome 42 引入字節(jié)碼緩存的原因。 該技術(shù)會(huì)本地緩存編譯過的代碼,這樣當(dāng)用戶返回同一頁面時(shí),諸如下載,解析和編譯等所有步驟都會(huì)被跳過。 這使得 Chrome 可以節(jié)省大約 40% 的解析和編譯時(shí)間。 此外,這還可以節(jié)省移動(dòng)設(shè)備的電量。
在 Opera 中,Carakan 引擎可以重用另一個(gè)程序最近編譯過的輸出。沒有要求代碼必須來自相同的頁面甚至同個(gè)域下。這種緩存技術(shù)實(shí)際上非常高效,還可以完全跳過編譯步驟。它依賴于典型的用戶行為和瀏覽場(chǎng)景:每當(dāng)用戶在應(yīng)用程序/網(wǎng)站中遵循某個(gè)用戶的特定瀏覽習(xí)慣,都會(huì)加載相同的 JavaScript 代碼。不過,Carakan 引擎早已被谷歌的 V8 所取代。
Opera 新的 JavaScript 引擎 “Carakan”,目前速度是其他已存在 JavaScript 引擎(基于 SunSpider)的2.5倍。其在轉(zhuǎn)化為本地機(jī)器代碼時(shí)專門針對(duì)正則表達(dá)式做了優(yōu)化。
Firefox 使用的 SpiderMonkey 引擎不會(huì)緩存所有內(nèi)容。它可以過渡到監(jiān)視階段,在這個(gè)階段中,它計(jì)算執(zhí)行給定腳本的次數(shù)?;诖擞?jì)算,它推導(dǎo)出頻繁使用而可以被優(yōu)化的代碼部分。
SpiderMonkey 是 Mozilla 項(xiàng)目的一部分,是一個(gè)用 C 語言實(shí)現(xiàn)的 JavaScript 腳本引擎,另外還有一個(gè)叫做Rhino 的 Java 版本。
顯然,有些人決定什么都不做。Safari 的首席開發(fā)人員 Maciej Stachowiak 表示,Safari 不會(huì)對(duì)編譯后的字節(jié)碼進(jìn)行任何緩存。緩存技術(shù)他們是有考慮過的問題,但是他們還沒有實(shí)現(xiàn),因?yàn)樯纱a的耗時(shí)小于總運(yùn)行時(shí)間的 2%。
這些優(yōu)化不會(huì)直接影響 JavaScript 源代碼的解析,但是會(huì)盡可能完全避免。畢竟做總比沒做好點(diǎn)?
我們可以做很多事情來改善應(yīng)用程序的初始加載時(shí)間。最小化加載的 JavaScript 數(shù)量:代碼越小、解析所需要時(shí)間就越少,運(yùn)行時(shí)間也就越小。要做到這一點(diǎn),我們只能在當(dāng)前的路由上加載所需的代碼,而不是加載一大陀的代碼。例如,PRPL模式即表示該種代碼傳輸類型?;蛘撸梢詸z查代碼的依賴關(guān)系,看看是否有什么冗余的依賴導(dǎo)致代碼庫膨脹,然而,這些東西需要很大的篇幅來進(jìn)行討論。
本文的主要的目的討論作為 Web 開發(fā)人員可以做些什么來幫助 JavaScript 解析器更快地完成它的工作。還有,現(xiàn)代JavaScript 解析器使用 啟發(fā)法(heuristics) 來決定是否立即運(yùn)行指定的代碼片段或者推遲在未來的某個(gè)時(shí)候運(yùn)行。基于這些啟發(fā)法,解析器將進(jìn)行即時(shí)或懶解析。
啟發(fā)法是針對(duì)模型求解方法而言的,是一種逐次逼近最優(yōu)解的方法。這種方法對(duì)所求得的解進(jìn)行反復(fù)判斷實(shí)踐修正直至滿意為止。啟發(fā)法的特點(diǎn)是模型簡(jiǎn)單,需要進(jìn)行方案組合的個(gè)數(shù)少,因此便于找出最終答案。此方法雖不能保證得到最優(yōu)解,但只要處理得當(dāng),可獲得決策者滿意的近似最優(yōu)解。一般步驟包括:定義一個(gè)計(jì)算總費(fèi)用的方法;報(bào)定判別準(zhǔn)則;規(guī)定方案改選的途徑;建立相應(yīng)的模型;送代求解。
立即解析會(huì)運(yùn)行需要立即編譯的函數(shù)。它主要做三件事:構(gòu)建 AST,構(gòu)建作用域?qū)蛹?jí)和查找所有語法錯(cuò)誤。另一方面, 懶解析只運(yùn)行未編譯的函數(shù)。它不構(gòu)建AST,也不查找所有語法錯(cuò)誤,它只構(gòu)建作用域?qū)蛹?jí),與立即解析相比節(jié)省了大約一半的時(shí)間。
顯然,這不是一個(gè)新概念。即使像 IE 9 這樣的瀏覽器也支持這種類型的優(yōu)化,盡管與現(xiàn)在的解析器的工作方式相比,這種優(yōu)化方式還很初級(jí)。
來看一個(gè)例子,假設(shè)有以下代碼片段:
function foo() { function bar(x) { return x + 10; } function baz(x, y) { return x + y; } console.log(baz(100, 200)); } foo()
就像前面的例子一樣,代碼被輸入到語法分析器中,語法分析器進(jìn)行語法分析并輸出AST,如下:
聲明函數(shù) foo
調(diào)用函數(shù) foo
在 foo 里聲明函數(shù) bar 接收參數(shù) x, 并返回 x 和 10 相加的結(jié)果
在 foo 里聲明函數(shù) baz 接收參數(shù) x和 y, 并返回 x 和 y 相加的結(jié)果
調(diào)用 baz 函數(shù)傳入 100 和 2。
調(diào)用 console.log 參數(shù)為之前函數(shù)調(diào)用的返回值。
那么期間發(fā)生了什么? 解析器看到 bar 函數(shù)的聲明、baz 函數(shù)的聲明、bar函數(shù)的調(diào)用和 console.log 的調(diào)用。但是,解析器做了一些完全無關(guān)的額外工作即解析 bar 函數(shù)。為什么這無關(guān)緊要? 因?yàn)楹瘮?shù) bar 從來沒有被調(diào)用過(或者至少在那個(gè)時(shí)候沒有)。這是一個(gè)簡(jiǎn)單的示例,看起來可能有些不同尋常,但在許多實(shí)際應(yīng)用程序中,許多聲明的函數(shù)從未被調(diào)用。
這里不解析bar函數(shù),該函數(shù)聲明了卻沒有調(diào)用它。只在需要的時(shí)候在函數(shù)運(yùn)行前進(jìn)行真正的解析。懶解析仍然需要找到函數(shù)的整個(gè)主體并為其聲明,但僅此而已。它不需要語法樹,因?yàn)樗€沒有被處理。另外,它不會(huì)從堆中分配內(nèi)存,而堆通常會(huì)占用相當(dāng)多的系統(tǒng)資源,簡(jiǎn)而言之,跳過這些步驟會(huì)帶來很大的性能改進(jìn)。
所以之前的例子,解析器實(shí)際上會(huì)像如下這樣解析:
注意,這里只確認(rèn) bar 函數(shù)聲明,沒有進(jìn)入 bar 函數(shù)體。在這種情況下,函數(shù)體只是一個(gè)返回語句。但是,與大多數(shù)實(shí)際應(yīng)用程序一樣,它可以更大,包含多個(gè)返回語句、條件語句、循環(huán)、變量聲明,甚至嵌套函數(shù)聲明。這完全是在浪費(fèi)時(shí)間和系統(tǒng)資源,因?yàn)檫@個(gè)函數(shù)永遠(yuǎn)不會(huì)被調(diào)用。
這是一個(gè)相當(dāng)簡(jiǎn)單的概念,但實(shí)際上,它的實(shí)現(xiàn)是非常難的,不局限于以上示例。整個(gè)方法還可以適用于函數(shù)、循環(huán)、條件、對(duì)象等。基本上,所有需要解析的東西。
例如,下面是一個(gè)非常常見的 JavaScript 模式。
var myModule = (function() { // 整個(gè)模塊的邏輯 // 返回模塊對(duì)象 })();
大多數(shù)現(xiàn)代 JavaScript 解析器都能識(shí)別這種模式,此模式表示代碼需要立即解析。
那么為什么解析器不都使用懶解析呢? 如果懶解析某些代碼,這些代碼需要立即執(zhí)行,這實(shí)際上會(huì)使代碼運(yùn)行速度變慢。需要運(yùn)行一次懶解析之后進(jìn)行另一個(gè)立即解析,這和立即解析相比,運(yùn)行速度會(huì)慢 50%。
現(xiàn)在對(duì)解析器底層原理有了大致的了解,是時(shí)候考慮如何提高解析器的解析速度??梢杂眠@種方式編寫代碼,以便在正確的時(shí)間解析函數(shù)。大多數(shù)解析器都能識(shí)別一種模式:使用括號(hào)封裝函數(shù)。對(duì)于解析器來說,這幾乎總是一個(gè)積極的信號(hào),即函數(shù)需要立即執(zhí)行。如果解析器看到一個(gè)左括號(hào),緊接著是一個(gè)函數(shù)聲明,它將立即解析這個(gè)函數(shù)??梢酝ㄟ^顯式地聲明立即執(zhí)行的函數(shù)來幫助解析器加快解析速度。
假設(shè)有一個(gè)名為 foo 的函數(shù)。
function foo(x) { return x * 10; }
因?yàn)闆]有明顯地標(biāo)識(shí)表明需要立即運(yùn)行該函數(shù)所以瀏覽器會(huì)進(jìn)行懶解析。然而,我們確定這是不對(duì)的,那么可以運(yùn)行兩個(gè)步驟。
首先,將函數(shù)存儲(chǔ)在一個(gè)變量中:
var foo = function foo(x) { return x * 10; };
注意,這里有使用函數(shù)的名稱 foo,這不是必需的,但是建議這樣做,因?yàn)樵趻伋霎惓5那闆r下,stacktrace 會(huì)保留實(shí)際函數(shù)名稱,而不僅僅是
以上事例解析器執(zhí)行懶解析,可以用括號(hào)封裝起來,讓解析器進(jìn)行立即解析:
var foo = (function foo(x) { return x * 10; });
現(xiàn)在,解析器看見 function 關(guān)鍵字前的左括號(hào)便會(huì)立即進(jìn)行解析。
因?yàn)樾枰澜馕銎髟谀男┣闆r下執(zhí)行懶解析或者立即解析,所以很難手動(dòng)管理。此外,還需要花時(shí)間考慮是否立即調(diào)用某個(gè)函數(shù),肯定沒人想這么做的。
最后,這種地讓代碼更難閱讀和理解??梢允褂?Optimize.js 可以幫我們做這類事情,該工具只是用來優(yōu)化 JavaScript 源代碼的初始加載時(shí)間,它們對(duì)代碼進(jìn)行靜態(tài)分析,然后通過使用括號(hào)封裝需要立即運(yùn)行的函數(shù)以便瀏覽器立即解析并準(zhǔn)備運(yùn)行它們。
像往常一樣編碼,然后有一段代碼看起來像這樣的:
(function() { console.log("Hello, World!"); })();
一切看起來都很好,如預(yù)期的那樣工作,而且速度很快,因?yàn)樵诤瘮?shù)聲明之前添加左括號(hào)。當(dāng)然,在進(jìn)入生產(chǎn)環(huán)境之前需要進(jìn)行代碼壓縮,以下為壓縮工具的輸出:
!function(){console.log("Hello, World!")}();
好像沒問題,代碼像以前一樣工作。但是好像少了什么,壓縮工具刪除包裹函數(shù)的括號(hào),而是在函數(shù)前放置了一個(gè)感嘆號(hào),這意味著解析器將跳過此并將執(zhí)行惰解析。
最重要的是,為了能夠執(zhí)行該函數(shù),它將在懶解析之后立即進(jìn)行立即解析。 這會(huì)使代碼運(yùn)行得更慢,幸運(yùn)的是,可以利用 Optimize.js 來解決此類問題,傳給 Optimize.js 壓縮過的代碼會(huì)輸出如下代碼:
!(function(){console.log("Hello, World!")})();
這還差不多,現(xiàn)在擁有兩全其美方案:壓縮代碼且解析器正確地識(shí)別懶解析和立即解析的函數(shù)。
預(yù)編譯但為什么不能在服務(wù)器端完成所有這些工作呢? 畢竟,最好這樣做一次并將結(jié)果提供給客戶端,而不強(qiáng)制各個(gè)客戶端重復(fù)做該項(xiàng)事情。那么,目前正在討論引擎是否應(yīng)該提供一種執(zhí)行預(yù)編譯腳本的方法,這樣就可以節(jié)省瀏覽器運(yùn)行時(shí)間。
從本質(zhì)上講,該思路是擁有可以生成字節(jié)碼的務(wù)器端工具,這樣只需要傳輸字節(jié)碼并在客戶端運(yùn)行,之后會(huì)看到啟動(dòng)時(shí)間的一些主要差異。 這可能聽起來很誘人,但事情并非那么簡(jiǎn)單,還可能會(huì)產(chǎn)生相反的效果,因?yàn)樗鼤?huì)更大,并且很可能需要簽署代碼并出于安全原因?qū)ζ溥M(jìn)行處理。 例如,V8 團(tuán)隊(duì)正在努力解決重復(fù)解析問題,這樣預(yù)編譯有可能實(shí)際并沒有多大的用處。
提升編譯速度一些建議檢查依賴,減少不必要的依賴
分割代碼為更小的塊而不是一整陀的
盡可能推遲加載 JavaScript,按需要加載或者動(dòng)態(tài)加載。
使用開發(fā)者工具和 DeviceTiming 來檢測(cè)性能瓶頸
用像 Optimize.js 的工具來幫助解析器選擇立即解析或者懶解析以加快解析速度
原文:
https://blog.sessionstack.com...
代碼部署后可能存在的BUG沒法實(shí)時(shí)知道,事后為了解決這些BUG,花了大量的時(shí)間進(jìn)行l(wèi)og 調(diào)試,這邊順便給大家推薦一個(gè)好用的BUG監(jiān)控工具 Fundebug。
你的點(diǎn)贊是我持續(xù)分享好東西的動(dòng)力,歡迎點(diǎn)贊!
交流干貨系列文章匯總?cè)缦?,覺得不錯(cuò)點(diǎn)個(gè)Star,歡迎 加群 互相學(xué)習(xí)。
https://github.com/qq44924588...
我是小智,公眾號(hào)「大遷世界」作者,對(duì)前端技術(shù)保持學(xué)習(xí)愛好者。我會(huì)經(jīng)常分享自己所學(xué)所看的干貨,在進(jìn)階的路上,共勉!
關(guān)注公眾號(hào),后臺(tái)回復(fù)福利,即可看到福利,你懂的。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/101269.html
摘要:事實(shí)是只是部分語言的不同表示法。基于這些,解析器會(huì)進(jìn)行立即或者懶解析。然而,解析器做了完全不相關(guān)的額外無用功即解析函數(shù)。這里不解析函數(shù),該函數(shù)聲明了卻沒有指出其用途。所以之前的例子,解析器實(shí)際上 原文請(qǐng)查閱這里,本文采用知識(shí)共享署名 4.0 國際許可協(xié)議共享,BY Troland。 本系列持續(xù)更新中,Github 地址請(qǐng)查閱這里。 這是 JavaScript 工作原理的第十四章。 概...
摘要:事實(shí)是只是部分語言的不同表示法?;谶@些,解析器會(huì)進(jìn)行立即或者懶解析。然而,解析器做了完全不相關(guān)的額外無用功即解析函數(shù)。這里不解析函數(shù),該函數(shù)聲明了卻沒有指出其用途。所以之前的例子,解析器實(shí)際上 原文請(qǐng)查閱這里,本文采用知識(shí)共享署名 4.0 國際許可協(xié)議共享,BY Troland。 本系列持續(xù)更新中,Github 地址請(qǐng)查閱這里。 這是 JavaScript 工作原理的第十四章。 概...
摘要:事實(shí)是只是部分語言的不同表示法?;谶@些,解析器會(huì)進(jìn)行立即或者懶解析。然而,解析器做了完全不相關(guān)的額外無用功即解析函數(shù)。這里不解析函數(shù),該函數(shù)聲明了卻沒有指出其用途。所以之前的例子,解析器實(shí)際上 原文請(qǐng)查閱這里,本文采用知識(shí)共享署名 4.0 國際許可協(xié)議共享,BY Troland。 本系列持續(xù)更新中,Github 地址請(qǐng)查閱這里。 這是 JavaScript 工作原理的第十四章。 概...
摘要:下面是用實(shí)現(xiàn)轉(zhuǎn)成抽象語法樹如下還支持繼承以下是轉(zhuǎn)換結(jié)果最終的結(jié)果還是代碼,其中包含庫中的一些函數(shù)??梢允褂眯碌囊子谑褂玫念惗x,但是它仍然會(huì)創(chuàng)建構(gòu)造函數(shù)和分配原型。 這是專門探索 JavaScript 及其所構(gòu)建的組件的系列文章的第 15 篇。 想閱讀更多優(yōu)質(zhì)文章請(qǐng)猛戳GitHub博客,一年百來篇優(yōu)質(zhì)文章等著你! 如果你錯(cuò)過了前面的章節(jié),可以在這里找到它們: JavaScript 是...
閱讀 2079·2023-04-25 22:58
閱讀 1432·2021-09-22 15:20
閱讀 2709·2019-08-30 15:56
閱讀 2005·2019-08-30 15:54
閱讀 2124·2019-08-29 12:31
閱讀 2743·2019-08-26 13:37
閱讀 608·2019-08-26 13:25
閱讀 2110·2019-08-26 11:58