扯不完的 JS 分號問題

mihan發表於2018-03-13

無論哪個團隊,程式碼風格統一的爭論是一個無解的話題,每次爭論起來,各有各理,或執著或偏激或喪心病狂拍桌憤然離去 :)

如果團隊強制性用了一種程式碼風格後,符合自己心中標準的同學,欣然樂嘻嘻;不符合的可能會心中『圈養』草泥馬闇然敲碼;最厲害的情況是,自己之前寫的程式碼在團隊流程工具統一編譯程式碼的時候被暗中格式化了,此時心中就不再是一圈草泥馬了,至少是一個動物公園。

我們之所以為程式碼風格統一爭論,因為大家都知道良好程式碼風格的重要性:專業、可維護,提高團隊協作效率。

然而,鄙人在不同的爭論會上以及網上各門各派的精彩舌戰中暗中觀察發現,某些程式碼風格支持者的支援理由看上去似乎並不是基於這個『重要性』或其更本質的觀點提出,而更像為自己貼上『個性程式碼』、『流行語言風格』、『我不喜歡』等標籤,如 JavaScript 分號大戰中,某乎上的一些『semicolon less』支持者觀點:

先看看最近一兩年最 Hit 的 @尤雨溪 大人:

沒有應該不應該,只有你自己喜歡不喜歡。JavaScript 語法長得 C-like 不代表它本質上和 C 是一類語言,所有直覺性的 “當然應該加分號” 都是保守的、未經深入思考的草率結論。後來新設計的語言裡可選分號的多得去了,光是 “可以加分號但是大家都不加” 的語言就有:Go, Scala, Ruby, Python, Swift, Groovy...

大 V 尤很介懷沒有深入去了解 ASI 機制就發表哪種好哪種不好的同學,而似乎更傾向將流行語言風格作為參考標準。

個人覺得並不是很有說服力,因為很容易讓我想到一個打比方:2012年西班牙的傳控踢法所向披靡,驚豔世界足壇,難道追求簡單實用的德國隊就一定要跟著踢傳控球才能說明自己是一支很優秀的球隊了嗎?說不通。

再來看看從 2012 年糾結到 2014 年的 @賀老溼

【2014年1月更新】當初鑑於本答案過長而可能導致部分“分號黨”無法catch到我的主要論點,原本打算重新修訂本答案。但是因時間精力因素未予重寫,且從本答案的支援來看,為分號正本清源的目的已經達到,所以不再修訂本答案。

這裡僅總結下“分號黨”推崇的“總是寫分號”風格的最主要缺陷:

  1. 人總是有可能忘記寫分號。ASI導致無法區分是無意中忘記還是有意不寫(程式碼折行)。
  2. “總是寫分號”並不能完全解決ASI缺陷(如return後換行會自動插入分號)。
  3. “}”後是否要加分號需要回溯到對應“{”之前進行語義判斷(是否是函式表示式),成本遠高於前置分號判斷(只要對行首字元進行token判斷:是否是 [ ( + - / 五個符號之一)。

用了很長很長的篇幅去回答,老溼這精神值得我們去學習。但是,老溼似乎是在放大加分號的各種缺點,然後給自己理由作出平衡,然後作出選擇。

我似乎同樣也不能接受這樣的理由,因為在實際編碼中,如果養成良好的編碼習慣,他所列的 1,2,3 缺陷根本不是問題。

其他一些觀點,很多都是隨著自己的喜愛隨性提出,如:

我是不加分號黨,不加分號讓程式碼更清新,對視覺的負擔也少一點

那有沒有實在一點的觀點?有的,@玉伯大神

看專案,如果是不加的專案,則不加,比如 zepto

如果是加的專案,則加上,比如 jquery

4 空格和 2 空格也是一樣,兩種風格我都習慣

很佛系很務實的答案是不是。實際工作中,就應該這樣,懂得『執生』,懂得尊重,為玉伯點 Like。可惜,這並不是一個可以說服你用還是不用分號的答案。

引發這些爭論,無非是風格問題,風格的東西,必定是個人偏愛的東西,圍著風格去討論,永遠都是口水戰,沒有結果。

所以,難道這個『分號問題』真的只是風格的問題?

引發分號的爭論問題,ASI 機制是最直接原因,那麼去了解為何會產生 ASI 是最容易著手的,而最捷徑的方法,就是去看看 JavaScript 的發明者 Brenden Eich 對這個問題的看法。正好有一篇文章就是他在 2012 年專門對這個問題發表的,The infernal semicolon(套路深)

文章開頭第一句就放了狠話

Most of the comments in this semicolons in JS exchange make me sad.

在這個 JS分號爭論 中的大多數評論讓我感到悲哀

這個爭論的標題是『bootstrap-dropdown.js clearMenus() needs ; at the end』,引發爭論的程式碼如下:

clearMenus()
!isActive && $parent.toggleClass('open')
複製程式碼

有人指出當時的 JSMin 有bug,壓縮上面的程式碼會出錯。

這時候,JSON、JSLint、JSMin 和 ADSafe 的創造者、ECMA JavaScript 2.0 標準化委員會委員、被 JavaScript 之父Brendan Eich 稱為 JavaScript 的大宗師、名著《JavaScript: The Good Parts》(中文版《JavaScript語言精粹》)的作者(來頭有點凶)Douglas Crockford 直接懟之:

That is insanely stupid code. I am not going to dumb down JSMin for this case.

TC39 is considering the use of ! as an infix operator. This code will break in the future. Fix it now. Learn to use semicolons properly. ! is not intended to be a statement separator. ; is.

這程式碼真尼瑪的瘋狂傻X,我是不會為了這傻X的案例而去降低 JSMin 的級數

TC39正在考慮將『!』號作為中綴運算子使用,這個程式碼不久將來就執行不了。趕緊修復吧,學學怎麼正確地使用分號。『!』號並不語句的分隔號,『;』才是。

Brendan Eich 對 Douglas Crockford 的回答以及強硬的態度婉轉表示贊同的同時,也保留了自己看法,大致思路如下:

用了不短的篇幅談了設計 ASI 的初衷:

ASI is (formally speaking) a syntactic error correction procedure. If you start to code as if it were a universal significant-newline rule, you will get into trouble

ASI是一個句法錯誤糾正的程式,如果你一開始編碼就將之視為普遍適用的新語句行規則,你會很大鍋

『句法錯誤糾正的程式』,我理解就是一個容錯方案,並不是一個語法規則!換個說法就是,我(當然是Brendan Eich)發明這個語言的時候,在語法上明確說明,一個句子的結束應該以『;』號作為結束,但是你們的編碼風格實在不可控,有可能會出現漏寫分號,為了防止你們在編碼過程中由於個人原因忘記加『;』號而造成錯誤,所以我加上 ASI 這個機制,儘可能地讓程式碼能正常地執行下去!

這似乎是作者當年的一番好意,如今卻成了一個爭論的話題,這並不是作者希望看到的,對這個現象,作者對 ASI 的設計表現出一絲絲悔意:

I wish I had made newlines more significant in JS back in those ten days in May, 1995

我多希望在 1995 年 5 月那 10 多天的日子裡,可以讓 JS 的斷句意義顯得更為重要(當時 Brendan Eich只用了10天的時間就把 JavaScript 設計出來了)。

但是從語言設計者的角度考慮,ASI 的存在似乎也是合理的,作者認為,一個程式語言在編碼風格自由度的把控並不可控,ASI 的設計可以讓其有更大的自由度:

Since when does any programming language not have syntax arguments? All living, practical languages that I know of, even those with indentation-based block structure and similar restrictions, have degrees of freedom of expression that allow abusage as well as good usage

有哪個程式語言是沒有語法上的爭論的?所有我瞭解的語言都有不錯的表達自由度,甚至一些基於縮排塊狀結構或與其有相似限制的語言有著同樣的表達自由度

Language designers can try to reduce degrees of freedom, but not eliminate them completely.

語言設計者可以嘗試降低自由度,卻不可能完完全全地將之限制死

最後,作者給了一個明確的觀點:

My two cents: be careful not to use ASI as if it gave JS significant newlines. And please don’t abuse && and || where the mighty if statement serves better.

注意不要使用ASI,儘管他給 JS 作了斷句判斷處理,如果強大的 if 語句可以正常使用的情況下,請不要濫用 && 和 ||

而站在語言設計者的角度,對語言自由度的把控,作者也表達了自己的態度:

I’ll also say that if it were up to me, in view of JS’s subtle and long history, I’d fix JSMin. But I would still log a grumpy comment or two first!

大致意思是,如果作者是 Douglas Crockford,縱觀 JS 的微妙而長遠的發展史,作者會修復 JSMin,但如果碰到 Douglas Crockford 所指的傻X程式碼,作者仍然會第一個站出來先怒懟幾句!

我們用自己的話來整理一下作者(下文的我)的觀點:

  • ASI 是一個句法錯誤糾正的程式,是我對語言設計自由度把控的態度
  • 很不幸,ASI 卻燃起了 JS 是否加分號編碼風格爭論戰火,粉絲們過激的行為使我感到很 Sad
  • 為此我感到後悔,希望自己在 95 年 5 月份的 10 多天設計時間裡可以讓 JS 的斷句意義顯得更為重要!
  • 但是我是一個很有態度的語言設計者,ASI 從語言設計角度上給予了語言更大的自由度,從這個層面上說,ASI 並沒有錯!
  • 繼續但是,可以正常擼通程式碼的情況下我還是不建議使用 ASI,畢竟 ASI 的設計是用來處理句法錯誤糾正的
  • 對於不尊重語言語法規範的傻 X 程式碼我依然會怒懟幾句,但是對語言設計自由度把控的態度我還是會堅持,所以我尊敬的大神 Douglas Crockford,如果我是你,我還是會怒懟傻 X 程式碼的,但同時我會修復 JSMin 以表作為一個語言設計者應有的態度。

OK,錘觀國內精彩的『分號大戰』,我也表達自己的兩個觀點:

  • 擼碼你可以我型我 show,但你首先得尊重語言本身;
  • 不要太迷信大 V 大神,應該要有自己的考究和判斷;

所以最後分號是加還是不加?

對天發誓,我

你們自己看著辦吧:)

相關文章