- JavaScript語(yǔ)言精髓與編程實(shí)踐(第3版)
- 周愛(ài)民
- 2540字
- 2020-07-02 15:37:32
1.7 JavaScript的應(yīng)用環(huán)境
在此前的內(nèi)容中,我們討論的都是JavaScript語(yǔ)言及其規(guī)范,而并非該語(yǔ)言的應(yīng)用環(huán)境。在大多數(shù)人看來(lái),JavaScript的應(yīng)用環(huán)境就是Web瀏覽器,這也的確是該語(yǔ)言最早的設(shè)計(jì)目標(biāo)。然而從很早開(kāi)始,JavaScript語(yǔ)言就已經(jīng)在其他的復(fù)雜應(yīng)用環(huán)境中使用,并受這些應(yīng)用環(huán)境的影響而發(fā)展出新的語(yǔ)言特性了。
JavaScript的應(yīng)用環(huán)境,主要由宿主環(huán)境與運(yùn)行期環(huán)境構(gòu)成。其中,宿主環(huán)境是指外殼程序(shell)和Web瀏覽器等,而運(yùn)行期環(huán)境則是由JavaScript引擎內(nèi)建的。圖1-9說(shuō)明了由宿主環(huán)境和運(yùn)行期環(huán)境共同構(gòu)建的對(duì)象編程系統(tǒng)的基本結(jié)構(gòu)。

圖1-9 由宿主環(huán)境與運(yùn)行期環(huán)境構(gòu)成的應(yīng)用環(huán)境
1.7.1 宿主環(huán)境
JavaScript是一門(mén)設(shè)計(jì)得相對(duì)“原始”的語(yǔ)言,它被創(chuàng)建時(shí)的最初目標(biāo)僅僅是為Netscape提供一門(mén)在瀏覽器與服務(wù)器間都能統(tǒng)一使用的開(kāi)發(fā)語(yǔ)言。簡(jiǎn)單地說(shuō),它原來(lái)的設(shè)計(jì)目標(biāo)是想讓B/S架構(gòu)兩端的開(kāi)發(fā)人員用起來(lái)都能舒服一些。這意味著最初的設(shè)計(jì)者希望JavaScript語(yǔ)言是跨平臺(tái)的,能夠提供“端到端(side to side)”的整體解決方案。
然而事實(shí)上這非常難做到,因?yàn)椴煌钠脚_(tái)提供的“可執(zhí)行環(huán)境”不同。而宿主環(huán)境(host environment)就是為了隔離代碼、語(yǔ)言與具體的平臺(tái)而提出的一種設(shè)計(jì)。一方面,我們不能讓瀏覽器中擁有一個(gè)巨大無(wú)比的運(yùn)行期環(huán)境(例如像虛擬機(jī)那么大);另一方面,服務(wù)器端又需要一個(gè)較強(qiáng)大的環(huán)境,因此JavaScript就被設(shè)計(jì)成了需要“宿主環(huán)境”的語(yǔ)言。
ECMAScript規(guī)范并沒(méi)有對(duì)宿主環(huán)境提出明確的定義。比如,它沒(méi)有提出標(biāo)準(zhǔn)輸入和標(biāo)準(zhǔn)輸出(stdin、stdout)需要確切地實(shí)現(xiàn)在哪個(gè)對(duì)象中。為了彌補(bǔ)這個(gè)問(wèn)題,RWC在WebAPI規(guī)范中首先就提出了“需要一個(gè)window對(duì)象”的瀏覽器環(huán)境。這意味著在RWC或者瀏覽器端,是以window對(duì)象及其中的Document對(duì)象來(lái)提供輸入輸出的。
但這仍然不是全部的真相。因?yàn)椤癛WC規(guī)范下的宿主環(huán)境”,并不等同于“JavaScript規(guī)范下的宿主環(huán)境”。本書(shū)也并不打算討論與特定瀏覽器相關(guān)的細(xì)節(jié)問(wèn)題,因此我們采用在多數(shù)宿主程序中的實(shí)現(xiàn):使用全局對(duì)象console來(lái)提供輸入輸出,如表1-2所示。
表1-2 本書(shū)對(duì)宿主環(huán)境在全局方法上的簡(jiǎn)單設(shè)定

1.7.2 外殼程序
外殼程序(shell)是宿主的一種。
不過(guò)在其他的一些文檔中并不這樣解釋?zhuān)窃噲D將宿主與外殼分別看待。其中的原因在于將“跨語(yǔ)言宿主”與“應(yīng)用宿主”混為一談。
在Windows環(huán)境中,微軟提供的WSH(Windows Script Host)是一種跨語(yǔ)言宿主,在該宿主環(huán)境中提供一個(gè)公共的對(duì)象系統(tǒng),并提供裝載不同的編程語(yǔ)言引擎的能力。如此一來(lái),WSH可以讓多種語(yǔ)言使用同一套對(duì)象—這些對(duì)象由一些COM組件來(lái)實(shí)現(xiàn)并注冊(cè)到Windows系統(tǒng)中。所以我們?cè)贗E瀏覽器中既可以用VBScript操作網(wǎng)頁(yè)中的對(duì)象,也可以用JScript來(lái)操作。基本上來(lái)講,IE瀏覽器采用的是與WSH完全相同的宿主實(shí)現(xiàn)技術(shù)。
多數(shù)JavaScript引擎會(huì)提供一個(gè)用于演示的外殼程序。該外殼程序通過(guò)一種命令行交互式界面來(lái)展示引擎的能力—在UNIX/Linux系統(tǒng)中編程的開(kāi)發(fā)人員會(huì)非常習(xí)慣這種環(huán)境,而在Windows中編程的開(kāi)發(fā)人員則不然。在這種環(huán)境下,可以像調(diào)試器中的單步跟蹤一樣,展示出許多引擎內(nèi)部的細(xì)節(jié)。圖1-10所示的是SpiderMonkey JavaScript隨引擎同時(shí)發(fā)布的一個(gè)外殼程序,它就是(該腳本引擎的)一個(gè)應(yīng)用宿主。
如同引擎提供的這種外殼程序,我們一般所見(jiàn)到的shell是指一種簡(jiǎn)單的應(yīng)用宿主,它只負(fù)責(zé)提供一個(gè)宿主應(yīng)用環(huán)境:包括對(duì)象和與對(duì)象運(yùn)行相關(guān)的操作系統(tǒng)進(jìn)程。但是在另外一些情況下,“外殼(而不是外殼程序)”和“宿主”也被賦予一些其他的含義。例如,在WSH中,“宿主”是指整個(gè)的宿主環(huán)境和提供該環(huán)境的技術(shù),而“shell”則是其中的一個(gè)可編程對(duì)象(WScript.WshShell)—封裝了Windows系統(tǒng)的功能(例如注冊(cè)表、文件系統(tǒng)等)的一個(gè)“外殼對(duì)象”,而非“外殼程序”。
而Node.js的情況比這些都要復(fù)雜。Node.js中的默認(rèn)JavaScript引擎是V8,這個(gè)腳本引擎可以連接到node主進(jìn)程的內(nèi)部,或者單獨(dú)以DLL(動(dòng)態(tài)鏈接庫(kù))的形式提供。所謂node主進(jìn)程,就是一個(gè)宿主,然而這個(gè)宿主如果以交互形式運(yùn)行,那么它又是一個(gè)傳統(tǒng)意義上的外殼程序。在后者這種情況下,開(kāi)發(fā)人員可以在命令行交互式界面上進(jìn)行測(cè)試、調(diào)試等,由其(動(dòng)態(tài)加載的)內(nèi)核模塊repl來(lái)提供支持。在這兩種模式下,Node.js都以全局的process對(duì)象來(lái)提供對(duì)宿主的訪(fǎng)問(wèn),例如可以通過(guò)process.moduleLoadList查看當(dāng)前裝載的模塊列表。

圖1-10 SpiderMonkey JavaScript提供的外殼程序
討論腳本引擎本身時(shí),我們并不強(qiáng)調(diào)宿主環(huán)境的形式是WSH這種“使用跨語(yǔ)言宿主技術(shù)構(gòu)建的腳本應(yīng)用環(huán)境”,還是SpiderMonkey JavaScript或Node.js所提供的這種“交互式命令行程序”。我們只強(qiáng)調(diào):腳本引擎必須運(yùn)行在一個(gè)宿主之中,并由該宿主創(chuàng)建和維護(hù)腳本引擎實(shí)例的“運(yùn)行期環(huán)境(runtime)”。
1.7.3 運(yùn)行期環(huán)境
不同的書(shū)籍對(duì)JavaScript運(yùn)行期(runtime)環(huán)境的闡釋是不一樣的。例如,在《JavaScript權(quán)威指南》中,它由“JavaScript內(nèi)核(Core)”和“客戶(hù)端(Client)JavaScript”兩部分構(gòu)成;而在《JavaScript高級(jí)程序設(shè)計(jì)》中,它被描述成由“核心(ECMAScript)”“文檔對(duì)象模型(DOM)”“瀏覽器對(duì)象模型(BOM)”三個(gè)部分組成(見(jiàn)圖1-11)。

圖1-11 對(duì)“運(yùn)行期環(huán)境”的不同解釋
本書(shū)是從引擎的角度討論JavaScript的,因此在本書(shū)看來(lái),與瀏覽器相關(guān)的內(nèi)容都屬于“應(yīng)用環(huán)境”:屬于宿主環(huán)境或?qū)儆谟脩?hù)編程環(huán)境。本小節(jié)開(kāi)始位置的圖1-9表達(dá)了這種關(guān)系。在這樣的關(guān)系中,運(yùn)行期環(huán)境是由宿主通過(guò)腳本引擎(JavaScript Engines)創(chuàng)建的。圖1-12說(shuō)明了應(yīng)用程序—宿主在這里可以看成一個(gè)應(yīng)用程序—如何創(chuàng)建運(yùn)行期環(huán)境。

圖1-12 應(yīng)用(宿主)通過(guò)引擎創(chuàng)建“運(yùn)行期環(huán)境”的過(guò)程
因此,在本書(shū)中講述的運(yùn)行期環(huán)境特指由引擎創(chuàng)建的初始應(yīng)用環(huán)境。主要包括:
■ 一個(gè)對(duì)宿主的約定。
■ 一個(gè)引擎內(nèi)核。
■ 一組對(duì)象和API。
■ 一些其他的規(guī)范。
我們這樣解釋運(yùn)行期環(huán)境的特點(diǎn),而并不強(qiáng)調(diào)(或包括)在應(yīng)用、宿主或用戶(hù)代碼混雜作用的、運(yùn)行過(guò)程中的應(yīng)用環(huán)境,就是要將討論聚焦于引擎自身的能力。不過(guò)即使如此,不同的JavaScript腳本引擎所提供的語(yǔ)言特性也并不一致。因此,在本書(shū)中若非特別說(shuō)明,JavaScript是指一種通用的、跨平臺(tái)的和跨環(huán)境的語(yǔ)言,并不特指某種特定的宿主環(huán)境或者運(yùn)行環(huán)境。也就是說(shuō),它是指ECMAScript-262所描述的語(yǔ)言規(guī)范。
1.7.4 兼容環(huán)境下的測(cè)試
本書(shū)撰寫(xiě)的代碼主要使用Node.js 4.x來(lái)進(jìn)行測(cè)試,但所有代碼全部經(jīng)過(guò)兼容性檢查,以確保它們?cè)贜ode.js 4.x之后的版本中表現(xiàn)一致(或?qū)τ胁町惖膬?nèi)容做出明確解釋?zhuān)?/p>
本書(shū)所述的兼容環(huán)境包括Chakra、JavaScriptCore、Node.js、SpiderMonkey、V8和xs。本書(shū)使用ESHOST和JSVU來(lái)構(gòu)建測(cè)試環(huán)境,并確保所有示例得到完整測(cè)試。讀者可以嘗試通過(guò)如下方式構(gòu)建相應(yīng)的測(cè)試環(huán)境。

需要留意的是,默認(rèn)情況下執(zhí)行jsvu總是更新全部最新版本的JavaScript引擎。你可以用如下命令行來(lái)切換不同的版本,或指定JSVU或ESHOST有選擇地管理哪些引擎。例如:

本書(shū)將通過(guò)開(kāi)源項(xiàng)目提供全部章節(jié)的示例和相關(guān)代碼,讀者可以參考閱讀。
- Python機(jī)器學(xué)習(xí):數(shù)據(jù)分析與評(píng)分卡建模(微課版)
- Cocos2d-x游戲開(kāi)發(fā):手把手教你Lua語(yǔ)言的編程方法
- JavaFX Essentials
- 數(shù)據(jù)結(jié)構(gòu)(Java語(yǔ)言描述)
- Mastering Julia
- Visual Basic學(xué)習(xí)手冊(cè)
- JavaScript by Example
- The DevOps 2.4 Toolkit
- 劍指MySQL:架構(gòu)、調(diào)優(yōu)與運(yùn)維
- Visual Basic程序設(shè)計(jì)實(shí)驗(yàn)指導(dǎo)(第二版)
- Getting Started with Eclipse Juno
- Android傳感器開(kāi)發(fā)與智能設(shè)備案例實(shí)戰(zhàn)
- CRYENGINE Game Development Blueprints
- 編程可以很簡(jiǎn)單
- Instant GLEW