日前,Reddit/Programming 頻道的頭條熱帖是一篇來自 julik live 博主的技術吐槽文,最初的英文標題是“For modern development Javascript indeed is a shit language”。該文在Reddit得分是800+,引發了熱評(930+評論)。感謝@蔡volvo蔡 的熱情翻譯,以下是譯文。
我很抱歉,但 Crockford 就是堅持這么寫的(I’m sorry, but the Crockford arguments do not cut it.)。
Javascript在很多方面都爛透了,而且還極其無趣,我就納了悶了,大家為啥都義無返顧,群情激奮的跳進Node學習的大軍里,是!Node是比Ruby快,Node是基于事件模型處理的,但讓我無法理解的是,一些人動不動就想把自己的程序用Node重構一下,過過腦子行嗎!
Javascript的繼承,深拷貝問題,不是定義一個新ECMA標準就能解決的,不是套個漂亮的語法外殼(比如Coffeescript)就能搞定的,不是用require實現個標準化或者引入classes就可以萬事大吉的,ECMA語言里不是有個引入classes的Actionscript嗎!那玩意跟Javascript一樣屎,只要大家繼續用它,PHP框架的現狀就是JS的未來— 一堆一堆的人前赴后繼,日以繼夜的為這坨屎一樣的語言搭框架、寫工具。
我來說一下為什么Javascript糟糕,當然了,它也有好的方面。 但是問題就是太不實用。比如說原型繼承(prototypal inheritance)就限制頗多-因為這玩意說白了就是function override,還有就是那句:“萬物皆function” 也是相當的廢柴-因為一function不是一個對象,也不能當做數據機構來承載數據。
其實真正的吐槽才剛剛開始,隨便列幾個吧:
JS的調用屬性
看這個屎一樣的設計,回顧過去,咱們很難苛責語言的設計人員,因為它們可能處于性能考慮,再者,如果不習慣消息-傳遞機制的語言的話,你會覺得怎么”一些屬性可以被調用而另外一些就不可以呢“!
哈希對象對于stable 鍵不可用
對象和哈希的混合不是一個好點子,因為它違反了對象可以擁有metadata的前提,metadata允許我們建立基本類型系統或者至少各種類型的introspection
函數對象對于類型系統不可用 因為一個對象不攜帶任何類型信息
這可是大事,Ruby的世界里也是這樣,感覺所有的東西都在像鴨子一樣快樂的嘎嘎叫,我們經常用Object$class 來獲取對象信息,下面是給HTML元素加樣式的標準的流程:
<div class=
'<%= model.class %>'
id=
'<%= [model.class, model.id].join %>'
>…
在JS里是不可能的,因為只有’Object’,’function’和原始類型才有類型信息
到處是Null
不小心用錯了一個常量
MyApp.SYNC
// should have been MyApp.SYNC_FETCH
任何事情都不會發生,因為對象是hashes,而且js給常量默認為0。 帶著錯誤key的常量將會是undefined,而且還會滲透到被調用函數中,等出了事,慢慢跟蹤debug去吧
回調的深淵
JS缺少合適的deferred功能,不是多線程,就得靠事件化執行,你的調用會散落在各個事件回調中,代碼都完事了,回調還在那執行呢,比如,JS干下面這個是就費勁
var
res = await AjaxReq.fetch(
'/long-request'
)
// because you are waiting for a result, here the runtime would
// schedule event handling, DOM redraws and whatever else it can
// squeeze in while you await
res.name
// this will be only executed once res is available
因為你在等一個結果,就在等待的這會,runtime完全可以進行事件處理、DOM重繪、干啥都行
res.name // this will be only executed once res is available 等res可以使用的時候在去執行res.name的操作
當然了,JS社區做了跟PHP社區一直以來一樣的事情-給Javascript這坨屎擦屁股,怎么擦呢?用更多的回調,好點的,就是回調鏈
when(<ERMAGHERD RIDICULOUSLY LONG CALLBACK>
// 48 lines of code down
).then(<HOLYSHIT WHEN WILL THIS BE OVER>
// 23 lines down
).then(<GIVE ME SOME COFFEE ALREADY>)
一般情況下,加入一個wait primitive就在獲取結果的等待過程中控制events,
專業一點的做法就是啥玩意咱都異步,現實是你寫的代碼80%都是同步的,因為程序里80%干的都是一個操蛋的事情跟另外一個操蛋的事情一起搞,而且你需要它倆都它媽的完事了才行。
可怕的異常處理機制
異常處理在JS中機器可怕,一般形式-你可以查看調用堆棧(一堆匿名函數和好點的名字的函數),你可看到錯誤信息,我就提兩個經常碰到的錯誤:
undefined is not a
function
cannot call property
'xyz'
of undefined
這都拜javascript中“函數對(泥煤)象”所賜,根本沒有方法定義-它們只有屬性,JS運行時永遠沒有辦法知道函數對象有沒有方法可以被調用,或者某個屬性名稱 – 它就認為你的哈希鍵不存在,
我記得Ruby社區里的人抱怨Ruby的回溯和錯誤消息機制不好用,Rubinius就給解決了,在泥煤的javascript里,你知道錯誤消息特別亂嗎?因為有你想得到和使用的兩個最最基本,最最重要的異常NameError和NoMethodError 都可能,這在其它語言里都是不能理解的,但javascript語言就這么馬馬虎虎的用起來了
不可否認,functions是亮點,原型也是好東西,但是如果你想建立一個稍微復雜的JS應用,你就得這么寫:
var
cv = Marionette.CollectionView.extend({
itemView: MyApp.Views.WidgetView;
});
如果”MyApp.Views.WidgetView 還沒有定義“你會得到啥錯誤?”undefined is not a function”當然!你什么時候會得到呢?當CollectionView想要實例化你的視圖的時候,而不是當你定義變量cv的時候,你會忐忑好幾分鐘,直到你明白了這錯誤是哪里導致的
這是為啥呢?因為所有都是hash而且這個語言不能做任何形式的introspection
還有一個困擾我的事就是有些大哥居然從Ruby轉戰Node,還贊Node是個好東西。Node也許是好寶貝,但是想想它內部運行著屎一樣的Javascript語言,我就由衷地想退避三舍。
這么說吧,JS一日不好用,我便一日不會用Node,謝謝
我理解有一些人想跳出MRI架構,投身Node,很簡單啊- -你不會說日語, 所以你舔個臉說日語很難學,話撂這,你在MRI上的有精進的機會也它媽趨近于0.
JS是屎,但凡我們有那么一絲絲的擔當,就該盡自己的綿薄之力要么讓它壽終正寢,要么幫助它更上一層樓,天天在那沾沾自喜對它的發展沒有一點幫助,Coffeescript做的還遠遠不夠。