Dart VS JavaScript之JavaScript的先天殘疾
敬告:本文作者沒寫過上萬行的代碼,文中信息全部為道聽途說,未經查證;文中觀點可能偏頗狹隘一根筋,謹做拋磚引玉之用。望達者查之,讀者自重,噴者迅猛。
Google 近日推出 Dart 語言,劍指大紅大紫的JavaScript。為什么Google 挑了這個看著不軟的柿子,Dart 能不能順利推倒傲嬌的 JavaScript,這篇文章主要分析這兩個口水側漏的問題。
JavaScript 和 Google 的蜜月
JavaScript 本來是 Netscape 的小打小鬧,可作為網頁動態腳本的開先河者,它第一個實現了對網頁動態指指畫畫的功能,必然隨著 Web 壯大而壯大。2005 年,AJAX 興起,網絡應用形勝,JavaScript 更是如日中天。盡管其它腳本語言(e.g.VBScript, Perl等)能實現相同功能,JavaScript 是唯一一個跨平臺跨設備瀏覽器都支持的語言。知名科技 Blog 摳腚好弱甚至說,所有能用 JavaScript 實現的,必將被 JavaScript 實現。
回顧 AJAX 的興起,Google 扮演了重要的推手角色。幾個標志性網絡服務 Gmail, Google Maps, Google Group,甚至 Google 搜索建議,都采用了 AJAX 實現。用戶端無需安裝任何插件,便有交互效果。榜樣的力量是無窮的,Google 的服務充分展現了 AJAX 的潛力,之后就是大家一擁而上,將 AJAX 捧到聚光燈下。考慮到 JavaScript 在 AJAX 之前都是小打小鬧,驗證個表單什么的,被人認為不堪大用。如果當時你說自己會 JavaScript 都沒人搭理你,怎么也要懂個 ASP/JSP 才拿得出手。當然也不是說 JavaScript 可有可無。就去年,我在網上訂機票,把身份證號填成手機號,竟然就注冊成功了,結果最后空姐不讓我登機!媽的,2010 年了,在網頁上加個 JavaScript 表單驗證會死么?分辨身份證號碼和手機號碼是尼瑪世界級難題么?跑題了,總之還是 Google 把 JavaScript 從小蘿莉帶入青春期。
AJAX 應用越來越多,JavaScript 代碼越來越多,短板也暴露的越來越明顯眾所周知,評判編程語言的標準和評判男人的標準不一樣。其中重要的一個標準是看編程語言有多快(嚴格地說,編程語言無快慢之分,編程語言的實現才有。為了語言簡潔,本文用編程語言快慢代指。)。而 JavaScript 最大的問題是,太!慢!了!
作為腳本語言,沒有事先編譯,性能完全靠瀏覽器里的 JavaScript 引擎。Google 在芬蘭找了一個團隊,閉門造車兩年打造出 V8 JavaScript 引擎,內置入 Chrome 瀏覽器。而 Chrome 在 08 年橫空出世,用幾百上千倍的 JavaScript 速度分數秒殺了當時市場上一切其它瀏覽器。自然,后來其它瀏覽器紛紛跟上,蘋果搞了 Safari Nitro 引擎,Mozilla 更新了各種猴子 JavaScript 引擎,連 IE 也不甘落后,搞出 Chakan 引擎各種提速,這貨雖說不比 Google Chrome V8 的速度,也聊勝于無。終于,JavaScript 引擎性能的突破使其能夠滿足現代網絡應用部署的需要。這次,Google 把 JavaScript 從含苞待放的青春前期催熟到青春后期。
吊詭的是,如今推出 Dart 語言的團隊便包含當年開發 V8 引擎的團隊。他們對 JavaScript 的評價是:“JavaScript 語言與生具來的殘疾是無法通過進化改善的。”
就是說,感情破裂了。
JavaScript 的非主流本質
究其原因,最大的瓶頸源于 JavaScript 是非主流語言的本質。
JavaScript 是基于原型(Prototype-based)的編程語言,而現在最主流的對象編程語言都是基于類(Class-based)的。兩者根本的區別在于,迥異的視角產生的不同方法論。。。
不嚴謹地說,基于類的語言邏輯來自分類學(Taxonomy),自上而下進行實現。程序員先要理清楚各種類之間的關系,定義好各種類,才能寫出類下面的實例(可用對象)。而基于原型的語言邏輯來自認知論,舉一反三進行實現,更符合人類正常認知的模式。程序員先關注幾個個例的具體行為,之后再分類使用。不恰當比喻說明,如果讓基于類的語言寫出一個男人,要先找到人類。然后創建一個男人子類,子類具有人類一切屬性且有男性性征。之后在男人子類創建出具體的男人甲。而基于原型的語言,可以先觀察女人和公猿,然后刪刪減減拼拼湊湊得到一個男人的原型,之后按照原形創建一個男人乙。
可以看出,基于類的編程主要方法是繼承,男人子類繼承了人類所有屬性,男人甲擁有男人子類所有屬性并賦了值,比如身高 175 體重 300 斤。而原型編程主要方法是克隆,男人原型克隆了女人的智商和皮膚屬性,公猿的性腺和嗓音屬性等等其它不細說了,請自行腦補。
計算機科學史上,先出現的是基于類的語言,后來才有基于原型的語言。前者在對象編程領域一直是主流,大學里教的主要是這個,多數研究也集中在這個領域。而原型編程,雖說由于 JavaScript 的存在使用的很多,但和基于類的編程相比還是非主流狀態。這就導致了一些相對劣勢。
由于缺乏對類的支持,而很多開發人員又習慣基于類編程。很多 JavaScript 庫模擬了自己的類對象,便于開發人員調用。看上去現在兩全齊美了,其實沒有。關鍵問題是,性能。
拜 Google 所賜,JavaScript 擁有目前世界上最有技術含量最復雜的腳本引擎,速度和其它腳本語言相比無以匹敵。Google 對 JavaScript 的最主要提速來自 JIT(Just-in-time) 編譯,把 JavaScript 預編譯成機器碼,在執行時直接調用機器碼提升效率。可跟傳統編譯語言比起來,性能不可同日而語;甚至比 JAVA, C# 也略遜一籌。
事實上,JavaScript 引擎相當復雜,且提速越來越難。這也跟 JavaScript 非主流原型編程有關。
基于類的語言,同類實例的數據結構和方法都相同,男人甲乙丙丁都有身高體重胸圍,無非是數值區別。這種情況下,腳本引擎只需要優化該類一次,生成本地碼,之后反復套用,自然會有效率性能提升。
而原型語言不同,沒有類的概念。傳統原型語言引擎的經典方法是給出一個大字典(HashMap),每次調用具體數值都去查字典,如此操作費時費力。可如果引擎按照類語言進行預編譯,又不知道編譯出來的本地碼后面是否被頻繁調用。有時甚至得不償失,花在預編譯上的時間還未必比查字典少。Google 的 V8 引擎則另辟蹊徑,分析發現 90% 的JavaScript object 是有規律可循的。于是他們總結規律,人為地生成隱藏類,對隱藏類進行優化編譯。當掃描的符合條件 JavaScript 代碼時,自動調用事先編譯好的機器碼執行。
現在你知道原型語言 JavaScript 為開發者和引擎造成了多大的擰巴。這種復雜性帶來的維護成本上升,開發門檻提高。要是用了主流類語言,不會有這么多麻煩。
JavaScript 本身缺乏很多特性,如不支持 Static Typing,調試維護相對困難;調用多個第三方庫難以保證不沖突;內置庫太迷你等等等等。當然這些都有解決方法。事實是,大多數 JavaScript 的粉絲也承認,JavaScript 是有一些缺陷的。
于是有了 Google Dart 語言,最核心的特性 1)基于類 2)可選類型(支持 dynamic/static typing)3)豐富內置庫 4)開發工具豐富。分別對應了上文提到的 JavaScript 缺陷。
下篇待續:Dart 的今生來世,主要分析 Dart 能否推倒青春后期的 JavaScript。
原文:http://www.guao.hk/posts/dart-vs-javascript-side-a-javascripts-legacy-problems.html
【編輯推薦】