JavaScript原理調(diào)研報(bào)告_第1頁
JavaScript原理調(diào)研報(bào)告_第2頁
JavaScript原理調(diào)研報(bào)告_第3頁
JavaScript原理調(diào)研報(bào)告_第4頁
JavaScript原理調(diào)研報(bào)告_第5頁
已閱讀5頁,還剩3頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

本文格式為Word版,下載可任意編輯——JavaScript原理調(diào)研報(bào)告

JavaScript原理調(diào)研報(bào)告李博杰PB

跟我同是2022級的一位同學(xué)在寫一本JavaScript原理方面的書(膜拜),他把正在寫的一片面內(nèi)容放在了博客上()他還基于JavaScript開發(fā)了一種類似CoffeeScript的新語言moescript,提升了好多語法糖,并將函數(shù)式特性發(fā)揮得淋漓盡致。

此調(diào)研報(bào)告就是跟著這些系列博客的路線,結(jié)合自己編寫JavaScript的體驗(yàn),參考ECMAScript5模范(JavaScript標(biāo)準(zhǔn))寫成的。

一、JavaScript中的this指針

下面是一段真實(shí)系統(tǒng)中的JavaScript代碼:

elseif(action==insert||action==replace){varvalues_str="("+t(teacher).map(db.escape).join(",")+")";

運(yùn)行這段代碼時(shí),會拋稀奇怪的奇怪,通過調(diào)用棧可以察覺,奇怪在db.escape內(nèi)部。db是一個(gè)數(shù)據(jù)庫連接對象,它的escape方法是將數(shù)據(jù)轉(zhuǎn)義,避開SQL語句中的特殊字符。這怎么會有問題呢?深入nodejs的數(shù)據(jù)庫引擎源碼才察覺,escape方法的調(diào)用鏈中需要獲取當(dāng)前時(shí)區(qū)one(雖然這跟escape無關(guān)),而escape內(nèi)部看到的this已經(jīng)不是db對象了!

遇到這個(gè)問題時(shí),我只是用簡樸方法解決了。系列博客的第一篇就解決了我的這個(gè)困惑。

在ECMAScript模范中,函數(shù)調(diào)用表達(dá)式有兩條產(chǎn)生式:

CallExpression-MemberExpressionArguments

CallExpression-CallExpressionArguments

這是為了遞歸調(diào)用。調(diào)用的"中心語'是MemberExpression。簡要調(diào)用過程如下:

1.計(jì)算MemberExpression得到ref2.計(jì)算Arguments3.假設(shè)ref不成調(diào)用,拋出奇怪4.假設(shè)ref是對象的方法,那么令this為這個(gè)對象5.假設(shè)ref不是對象的方法,那么令this為調(diào)用者環(huán)境中的this6.用this和arguments調(diào)用ref在上面的問題代碼中,將db.escape傳給了map,在map的內(nèi)部實(shí)現(xiàn)中調(diào)用它的時(shí)候,JavaScript引擎已經(jīng)不知道它來自db對象,也就是上述第4條不得志,進(jìn)入第5條,escape中看到的this變成了調(diào)用者map看到的this,這鮮明不是db。

在正常的db.escape調(diào)用中,得志上述第4條判斷,因此被調(diào)用者看到的this就是正確的db對象了。

二、eval對象為什么要加括號不借助類庫寫過ajax(欣賞器異步通信)的JavaScript程序員都知道,要想把返回的json(JavaScriptObjectNotation)字符串變成一個(gè)對象以便使用,務(wù)必用obj=eval("("+str+")")

為什么要加那一對括號呢?Google一下就知道,JavaScript規(guī)定表達(dá)式語句不能用花括號開頭,而json對象是用花括號括起來的。系列博客的其次篇解釋了JavaScript這樣設(shè)計(jì)的理由。

看這行代碼:

{a:1}它有兩種解釋:

1.一個(gè)JavaScript對象,有一個(gè)名為a、值為1的元素2.一個(gè)JavaScript語句塊,a是標(biāo)號,語句體是1。由于JavaScript在特定處境下允許省略分號,上述語句塊是合法的。

這樣就帶來了語法上的歧義,務(wù)必解決。

ECMAScript模范的手段很簡樸,就是規(guī)定該展現(xiàn)語句塊的地方不能展現(xiàn)JavaScript對象字面量,也就是語句塊不能單由一個(gè)對象字面量構(gòu)成。為了讓對象字面量能在eval中作為代碼執(zhí)行,只好把它當(dāng)作表達(dá)式,包在圓括號中間了。

這篇博文還分析了JavaScript允許這么古怪的語句塊(上述其次種解釋)存在的理由。由于JavaScript是90年頭研發(fā)的,當(dāng)時(shí)的主流語言都支持懸空語句塊,也就是沒有任何for,if之類前綴的語句塊,或者說對應(yīng)這樣的產(chǎn)生式:

Block-{StatementList}事實(shí)上,C語言中這樣的語句塊能產(chǎn)生新的作用域,還算有點(diǎn)用;但JavaScript的語句塊不變更作用域,因此這樣的懸空語句塊除了裝飾以外沒什么用。悵然,JavaScript不能免俗,沒有割掉"懸空語句塊'這塊贅肉。

三、語法糖與分號癌JavaScript中的自動插入分號是一個(gè)"可怕'的特性。在前端JavaScript代碼中,我曾經(jīng)遇到了類似這樣的古怪問題:

varx={

"i":1,

"j":2}

//Nosemicolonhere.[normalVersion,ffVersion][isIE]();JavaScript不會自動補(bǔ)全方法聲明后面的分號,而是將對象字面值和方法調(diào)用當(dāng)成了同一條語句。

第三篇文章指出,JavaScript自動補(bǔ)全分號事實(shí)上是在解釋換行一種解釋是分號,另一種解釋是空格。假設(shè)沒有歧義,也就是另一種解釋會導(dǎo)致不正確的JavaScript語法,就會作出唯一的解釋;假設(shè)兩種解釋都是合法的JavaScript,那么會解釋成空格。這就是前面悲劇代碼的起因了。

為什么默認(rèn)解釋為空格呢?由于JavaScript那個(gè)時(shí)代的語言繼承了C的遺風(fēng),允許這樣的代碼:

vara=f(b+c)它的意思是vara=f(b+c)。

今天流行的Python、Ruby之類編程語言"根據(jù)縮進(jìn)抉擇程序布局'的風(fēng)格,還遠(yuǎn)遠(yuǎn)沒有流行開來。我認(rèn)為,可能是由于編輯器的變化。在90年頭,圖形界面和網(wǎng)絡(luò)尚未普及,程序要印到紙上才能傳播,屏幕的字符寬度又只有80個(gè),程序經(jīng)常需要換行,

因此程序語言的設(shè)計(jì)者將換行看成是跟空格一樣。但今天我們的程序都通過網(wǎng)絡(luò)傳播,圖形界面也賦予了一行顯示更多字符的才能,用換行替代空格并不多見。

這篇文章細(xì)致說領(lǐng)略,從上述"消釋歧義'的解釋,是如何一步步導(dǎo)出ECMAScript模范中的三條拗口的分號插入規(guī)定的。接著提出了一種消釋換行歧義的JavaScript文法。當(dāng)然,這樣的文法會變得面目全非,因此面對換行歧義,ECMAScript模范的處理方法跟經(jīng)典的if-else歧義一樣,都是用"例外規(guī)矩'來定義,而非修改文法使其沒有歧義。

四、JavaScript正規(guī)式與詞法分析中的特殊模式這個(gè)系列目前為止的結(jié)果一篇文章提到了JavaScript中的轉(zhuǎn)義字符和正那么表達(dá)式。JavaScript中的正那么表達(dá)式是用一種特殊的語法來聲明的,這使得語法分析變得繁雜。譬如a/b/g詞法層面上有兩種解釋:

1.a除以b,再除以g2.一個(gè)標(biāo)識符a,模式b,模式限定符g(表示global)

由于JavaScript文法中標(biāo)識符后不能接模式,上述第2種解釋是不成立的。不過上述判斷只能在語法層面得出,這給基于詞法分析的語法高亮器帶來了麻煩。

我想到上學(xué)期編譯原理測驗(yàn)中解析PHP的lex文法,使用了狀態(tài)機(jī)的手段。PHP中有類似bash和Perl的對比奇葩的語法:

"$var$arr[0]$arr[$index]${varname}'上述變量和數(shù)組元素的值會被替換進(jìn)字符串。字符串不再是一個(gè)詞法元素(終結(jié)符),而是一個(gè)非終結(jié)符,包含了更繁雜的語法布局。問題來了:"function'展現(xiàn)在字符串里就是字面值,展現(xiàn)在外面就是關(guān)鍵字,基于正那么表達(dá)式的詞法分析很難辨識出兩者的識別。

PHP引擎對這種處境的處理,就是lex在主模式中遇到雙引號(字符串的起始標(biāo)志)時(shí),就進(jìn)入一種特殊模式(引用模式),這個(gè)模式中所用的正那么式與外面不同,從而能夠正確得到字符串內(nèi)的詞法元素,又不讓這些特殊正那么式"污染'外面的詞法分析。當(dāng)lex在引用模式內(nèi)匹配上配對的雙引號時(shí),再返回主模式。

轉(zhuǎn)義字符也可以用類似的方法處理。我不知道JavaScript引擎是如何匹配正規(guī)式的,但我認(rèn)為可以用類似的機(jī)制實(shí)現(xiàn)。正規(guī)式可能比前面提到的PHP例子更繁雜,由于需要語法分析來消釋歧義,也就是需要yacc給lex供給"下一終結(jié)符是否可能是正規(guī)式'的信息。lex知道下一終結(jié)符可能是正規(guī)式,并匹配上開頭標(biāo)志"/'時(shí),就可以進(jìn)入狀態(tài)機(jī),利用括號配對原那么,一個(gè)一個(gè)字符地吃進(jìn)去,直到遇到配對的終止標(biāo)志"/',此時(shí)lex就能把匹配到的片面作為正規(guī)式終結(jié)符返回給yacc。

五、動態(tài)作用域與靜態(tài)作用域在函數(shù)式語言中,閉包是進(jìn)化的產(chǎn)物,而不是"與生俱來'的。這是從王垠關(guān)于Lisp的文章()里看到的。

在折騰Emacs的時(shí)候察覺它的Elisp分外難以理解,其主要理由就是Lisp初始版本采用的動態(tài)作用域。也就是假設(shè)一個(gè)函數(shù)中存在自由變量,這個(gè)自由變量是到它的調(diào)用者那里去找。當(dāng)然Emacs最新版本已經(jīng)改掉了Elisp的動態(tài)作用域。

Lisp最初為什么要采用這樣"不成理喻'的動態(tài)作用域呢?由于實(shí)現(xiàn)簡樸。Lisp把函

數(shù)保存成一個(gè)S表達(dá)式,調(diào)用的時(shí)候要傳函數(shù),就把這個(gè)S表達(dá)式傳進(jìn)去了。函數(shù)調(diào)用是基于堆棧的,S表達(dá)式求值的過程中遇到自由變量,就順著堆棧往上找,找到哪個(gè)就用哪個(gè)。這種語義的問題是,自由變量的值會隨著調(diào)用棧上相隔好幾層的毫無關(guān)系的變量值變更,這不利于程序的封裝。王垠說,LispMachine失敗的理由就在此。

因此,現(xiàn)在的函數(shù)式語言,如Haskell、JavaScript,都是采用靜態(tài)作用域。也就是函數(shù)中的自由變量到它的定義處去找。這就需要為每個(gè)函數(shù)創(chuàng)造一個(gè)"閉包',也就是定義此函數(shù)的執(zhí)行環(huán)境。由于函數(shù)定義處的環(huán)境以后還可能使用,這個(gè)環(huán)境在函數(shù)執(zhí)行終止后并不能連忙釋放。因此執(zhí)行環(huán)境不能放在棧里,而要放在堆里。這不僅增加了實(shí)現(xiàn)的繁雜度,還給垃圾回收增加了麻煩。編譯器務(wù)必有手段知道閉包的全體引用是否已經(jīng)全部失效,否那么就無法釋放閉包占用的內(nèi)存。

六、與本文主題無關(guān)的補(bǔ)充順便提一句,前面提到的博客及其友情鏈接中還有不少關(guān)于程序設(shè)計(jì)語言

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論