JS 中扯不完的分號(hào)問題

前言

無論哪個(gè)團(tuán)隊(duì)血崭,代碼風(fēng)格統(tǒng)一的爭(zhēng)論是一個(gè)無解的話題本股,每次爭(zhēng)論起來混狠,各有各理屑墨,或執(zhí)著或偏激或喪心病狂拍桌憤然離去 :)
如果團(tuán)隊(duì)強(qiáng)制性用了一種代碼風(fēng)格后躁锁,符合自己心中標(biāo)準(zhǔn)的同學(xué),欣然樂嘻嘻卵史;不符合的可能會(huì)心中『圈養(yǎng)』草泥馬暗然敲碼战转;最厲害的情況是,自己之前寫的代碼在團(tuán)隊(duì)流程工具統(tǒng)一編譯代碼的時(shí)候被暗中格式化了以躯,此時(shí)心中就不再是一圈草泥馬了槐秧,至少是一個(gè)動(dòng)物公園。

我們之所以為代碼風(fēng)格統(tǒng)一爭(zhēng)論,因?yàn)榇蠹叶贾懒己么a風(fēng)格的重要性:專業(yè)刁标、可維護(hù)颠通,提高團(tuán)隊(duì)協(xié)作效率。

扯不完的分號(hào)問題

某些代碼風(fēng)格支持者的支持理由看上去似乎并不是基于這個(gè)『重要性』或其更本質(zhì)的觀點(diǎn)提出命雀,而更像為自己貼上『個(gè)性代碼』蒜哀、『流行語言風(fēng)格』、『我不喜歡』等標(biāo)簽吏砂,如 JavaScript 分號(hào)大戰(zhàn)中撵儿,某乎上的一些『semicolon less』支持者觀點(diǎn):

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

沒有應(yīng)該不應(yīng)該,只有你自己喜歡不喜歡狐血。JavaScript 語法長(zhǎng)得 C-like 不代表它本質(zhì)上和 C 是一類語言淀歇,所有直覺性的 “當(dāng)然應(yīng)該加分號(hào)” 都是保守的、未經(jīng)深入思考的草率結(jié)論匈织。后來新設(shè)計(jì)的語言里可選分號(hào)的多得去了浪默,光是 “可以加分號(hào)但是大家都不加” 的語言就有:Go, Scala, Ruby, Python, Swift, Groovy...

大 V 尤很介懷沒有深入去了解 ASI 機(jī)制就發(fā)表哪種好哪種不好的同學(xué),而似乎更傾向?qū)⒘餍姓Z言風(fēng)格作為參考標(biāo)準(zhǔn)缀匕。

個(gè)人覺得并不是很有說服力纳决,因?yàn)楹苋菀鬃屛蚁氲揭粋€(gè)打比方:2012年西班牙的傳控踢法所向披靡,驚艷世界足壇乡小,難道追求簡(jiǎn)單實(shí)用的德國(guó)隊(duì)就一定要跟著踢傳控球才能說明自己是一支很優(yōu)秀的球隊(duì)了嗎阔加?說不通。

再來看看從 2012 年糾結(jié)到 2014 年的 @賀老濕:

【2014年1月更新】當(dāng)初鑒于本答案過長(zhǎng)而可能導(dǎo)致部分“分號(hào)黨”無法catch到我的主要論點(diǎn)满钟,原本打算重新修訂本答案胜榔。但是因時(shí)間精力因素未予重寫,且從本答案的支持來看湃番,為分號(hào)正本清源的目的已經(jīng)達(dá)到夭织,所以不再修訂本答案。

這里僅總結(jié)下“分號(hào)黨”推崇的“總是寫分號(hào)”風(fēng)格的最主要缺陷:

  1. 人總是有可能忘記寫分號(hào)吠撮。ASI導(dǎo)致無法區(qū)分是無意中忘記還是有意不寫(代碼折行)尊惰。
  2. “總是寫分號(hào)”并不能完全解決ASI缺陷(如return后換行會(huì)自動(dòng)插入分號(hào))。
  3. “}”后是否要加分號(hào)需要回溯到對(duì)應(yīng)“{”之前進(jìn)行語義判斷(是否是函數(shù)表達(dá)式)泥兰,成本遠(yuǎn)高于前置分號(hào)判斷(只要對(duì)行首字符進(jìn)行token判斷:是否是 [ ( + - / 五個(gè)符號(hào)之一)择浊。

用了很長(zhǎng)很長(zhǎng)的篇幅去回答,老濕這精神值得我們?nèi)W(xué)習(xí)逾条。但是琢岩,老濕似乎是在放大加分號(hào)的各種缺點(diǎn),然后給自己理由作出平衡师脂,然后作出選擇担孔。

我似乎同樣也不能接受這樣的理由江锨,因?yàn)樵趯?shí)際編碼中糕篇,如果養(yǎng)成良好的編碼習(xí)慣啄育,他所列的 1,2拌消,3 缺陷根本不是問題挑豌。

其他一些觀點(diǎn),很多都是隨著自己的喜愛隨性提出墩崩,如:

我是不加分號(hào)黨氓英,不加分號(hào)讓代碼更清新,對(duì)視覺的負(fù)擔(dān)也少一點(diǎn)

那有沒有實(shí)在一點(diǎn)的觀點(diǎn)鹦筹?有的铝阐,@玉伯大神的

看項(xiàng)目,如果是不加的項(xiàng)目铐拐,則不加徘键,比如 zepto

如果是加的項(xiàng)目,則加上遍蟋,比如 jquery

4 空格和 2 空格也是一樣吹害,兩種風(fēng)格我都習(xí)慣

很佛系很務(wù)實(shí)的答案是不是。實(shí)際工作中虚青,就應(yīng)該這樣它呀,懂得『執(zhí)生』,懂得尊重挟憔,為玉伯點(diǎn) Like⊙毯牛可惜绊谭,這并不是一個(gè)可以說服你用還是不用分號(hào)的答案。

引發(fā)這些爭(zhēng)論汪拥,無非是風(fēng)格問題达传,風(fēng)格的東西,必定是個(gè)人偏愛的東西迫筑,圍著風(fēng)格去討論宪赶,永遠(yuǎn)都是口水戰(zhàn),沒有結(jié)果脯燃。

所以搂妻,難道這個(gè)『分號(hào)問題』真的只是風(fēng)格的問題?

引發(fā)分號(hào)的爭(zhēng)論問題辕棚,ASI 機(jī)制是最直接原因欲主,那么去了解為何會(huì)產(chǎn)生 ASI 是最容易著手的邓厕,而最捷徑的方法,就是去看看 JavaScript 的發(fā)明者 Brenden Eich 對(duì)這個(gè)問題的看法扁瓢。正好有一篇文章就是他在 2012 年專門對(duì)這個(gè)問題發(fā)表的详恼,The infernal semicolon(套路深)

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

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

在這個(gè) JS分號(hào)爭(zhēng)論 中的大多數(shù)評(píng)論讓我感到悲哀

這個(gè)爭(zhēng)論的標(biāo)題是『bootstrap-dropdown.js clearMenus() needs ; at the end』,引發(fā)爭(zhēng)論的代碼如下:

clearMenus()
!isActive && $parent.toggleClass('open')

復(fù)制代碼有人指出當(dāng)時(shí)的 JSMin 有bug引几,壓縮上面的代碼會(huì)出錯(cuò)昧互。

這時(shí)候,JSON伟桅、JSLint敞掘、JSMin 和 ADSafe 的創(chuàng)造者、ECMA JavaScript 2.0 標(biāo)準(zhǔn)化委員會(huì)委員贿讹、被 JavaScript 之父Brendan Eich 稱為 JavaScript 的大宗師渐逃、名著《JavaScript: The Good Parts》(中文版《JavaScript語言精粹》)的作者(來頭有點(diǎn)兇)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.

這代碼真尼瑪?shù)寞偪裆礨,我是不會(huì)為了這傻X的案例而去降低 JSMin 的級(jí)數(shù)
TC39正在考慮將『!』號(hào)作為中綴運(yùn)算符使用民褂,這個(gè)代碼不久將來就運(yùn)行不了茄菊。趕緊修復(fù)吧,學(xué)學(xué)怎么正確地使用分號(hào)赊堪∶嬷常『!』號(hào)并不是語句的分隔號(hào),『;』才是哭廉。

Brendan Eich 對(duì) Douglas Crockford 的回答以及強(qiáng)硬的態(tài)度婉轉(zhuǎn)表示贊同的同時(shí)脊僚,也保留了自己看法,大致思路如下:
用了不短的篇幅談了設(shè)計(jì) 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是一個(gè)句法錯(cuò)誤糾正的程式遵绰,如果你一開始編碼就將之視為普遍適用的新語句行規(guī)則辽幌,你會(huì)很大鍋

『句法錯(cuò)誤糾正的程式』,我理解就是一個(gè)容錯(cuò)方案椿访,并不是一個(gè)語法規(guī)則乌企!換個(gè)說法就是,我(當(dāng)然是Brendan Eich)發(fā)明這個(gè)語言的時(shí)候成玫,在語法上明確說明加酵,一個(gè)句子的結(jié)束應(yīng)該以『;』號(hào)作為結(jié)束,但是你們的編碼風(fēng)格實(shí)在不可控哭当,有可能會(huì)出現(xiàn)漏寫分號(hào)猪腕,為了防止你們?cè)诰幋a過程中由于個(gè)人原因忘記加『;』號(hào)而造成錯(cuò)誤,所以我加上 ASI 這個(gè)機(jī)制钦勘,盡可能地讓代碼能正常地運(yùn)行下去陋葡!

這似乎是作者當(dāng)年的一番好意,如今卻成了一個(gè)爭(zhēng)論的話題彻采,這并不是作者希望看到的脖岛,對(duì)這個(gè)現(xiàn)象朵栖,作者對(duì) ASI 的設(shè)計(jì)表現(xiàn)出一絲絲悔意:

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

? 我多希望在 1995 年 5 月那 10 多天的日子里,可以讓 JS 的斷句意義顯得更為重要(當(dāng)時(shí) Brendan Eich只用了10天的時(shí)間就把 JavaScript 設(shè)計(jì)出來了)柴梆。

但是從語言設(shè)計(jì)者的角度考慮陨溅,ASI 的存在似乎也是合理的,作者認(rèn)為绍在,一個(gè)編程語言在編碼風(fēng)格自由度的把控并不可控门扇,ASI 的設(shè)計(jì)可以讓其有更大的自由度:

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

有哪個(gè)編程語言是沒有語法上的爭(zhēng)論的?所有我了解的語言都有不錯(cuò)的表達(dá)自由度偿渡,甚至一些基于縮進(jìn)塊狀結(jié)構(gòu)或與其有相似限制的語言有著同樣的表達(dá)自由度

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

語言設(shè)計(jì)者可以嘗試降低自由度臼寄,卻不可能完完全全地將之限制死

最后,作者給了一個(gè)明確的觀點(diǎn):

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 作了斷句判斷處理吉拳,如果強(qiáng)大的 if 語句可以正常使用的情況下,請(qǐng)不要濫用 && 和 ||

而站在語言設(shè)計(jì)者的角度适揉,對(duì)語言自由度的把控留攒,作者也表達(dá)了自己的態(tài)度:

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 的微妙而長(zhǎng)遠(yuǎn)的發(fā)展史炼邀,作者會(huì)修復(fù) JSMin,但如果碰到 Douglas Crockford 所指的傻X代碼剪侮,作者仍然會(huì)第一個(gè)站出來先怒懟幾句拭宁!

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

  • ASI 是一個(gè)句法錯(cuò)誤糾正的程式,是我對(duì)語言設(shè)計(jì)自由度把控的態(tài)度
  • 很不幸瓣俯,ASI 卻燃起了 JS 是否加分號(hào)編碼風(fēng)格爭(zhēng)論戰(zhàn)火杰标,粉絲們過激的行為使我感到很 Sad
  • 為此我感到后悔,希望自己在 95 年 5 月份的 10 多天設(shè)計(jì)時(shí)間里可以讓 JS 的斷句意義顯得更為重要彩匕!
  • 但是我是一個(gè)很有態(tài)度的語言設(shè)計(jì)者腔剂,ASI 從語言設(shè)計(jì)角度上給予了語言更大的自由度,從這個(gè)層面上說推掸,ASI 并沒有錯(cuò)桶蝎!
  • 繼續(xù)但是驻仅,可以正常擼通代碼的情況下我還是不建議使用 ASI谅畅,畢竟 ASI 的設(shè)計(jì)是用來處理句法錯(cuò)誤糾正的
  • 對(duì)于不尊重語言語法規(guī)范的傻 X 代碼我依然會(huì)怒懟幾句,但是對(duì)語言設(shè)計(jì)自由度把控的態(tài)度我還是會(huì)堅(jiān)持噪服,所以我尊敬的大神 Douglas Crockford毡泻,如果我是你,我還是會(huì)怒懟傻 X 代碼的粘优,但同時(shí)我會(huì)修復(fù) JSMin 以表作為一個(gè)語言設(shè)計(jì)者應(yīng)有的態(tài)度仇味。

自動(dòng)分號(hào)插入機(jī)制 ASI

JavaScript 有著自動(dòng)分號(hào)插入的機(jī)制(Automatic Semicolon Insertion)呻顽,簡(jiǎn)稱 ASI。這是一個(gè)輔助性的功能丹墨,然后有一些情況要注意:

如果你這樣寫代碼:

return 
a + b

那么自動(dòng)分號(hào)插入后會(huì)這樣:

return;
a + b;

更可能導(dǎo)致隱含BUG的狀況是:

a = b + c
(d + e).print()

他不會(huì)自動(dòng)插入分號(hào)廊遍,因?yàn)榈诙幸焕ㄌ?hào)開始,會(huì)被誤認(rèn)為是函數(shù)贩挣。

a = b + c(d + e).print();

那么這樣看來喉前,用分號(hào)才是最安全的做法咯!

如果你不想用分號(hào)王财,又怕出問題卵迂,v2ex 上有位童鞋給出了一個(gè)速記方案:

如果你寫 JS 代碼不喜歡帶分號(hào),而又搞不清什么時(shí)候必須加分號(hào)绒净,可以這么做:

  • 在以 "("见咒、"[" 、"/"挂疆、"+"改览、"-" 開頭的語句前面都加上一個(gè)分號(hào)。

參考

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末恃疯,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子墨闲,更是在濱河造成了極大的恐慌今妄,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,997評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鸳碧,死亡現(xiàn)場(chǎng)離奇詭異盾鳞,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)瞻离,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,603評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門腾仅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人套利,你說我怎么就攤上這事推励。” “怎么了肉迫?”我有些...
    開封第一講書人閱讀 163,359評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵验辞,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我喊衫,道長(zhǎng)跌造,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,309評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮壳贪,結(jié)果婚禮上陵珍,老公的妹妹穿的比我還像新娘。我一直安慰自己违施,他們只是感情好互纯,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,346評(píng)論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著磕蒲,像睡著了一般伟姐。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上亿卤,一...
    開封第一講書人閱讀 51,258評(píng)論 1 300
  • 那天愤兵,我揣著相機(jī)與錄音,去河邊找鬼排吴。 笑死秆乳,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的钻哩。 我是一名探鬼主播屹堰,決...
    沈念sama閱讀 40,122評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼街氢!你這毒婦竟也來了扯键?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,970評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤珊肃,失蹤者是張志新(化名)和其女友劉穎荣刑,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體伦乔,經(jīng)...
    沈念sama閱讀 45,403評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡厉亏,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,596評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了烈和。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片爱只。...
    茶點(diǎn)故事閱讀 39,769評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖招刹,靈堂內(nèi)的尸體忽然破棺而出恬试,到底是詐尸還是另有隱情,我是刑警寧澤疯暑,帶...
    沈念sama閱讀 35,464評(píng)論 5 344
  • 正文 年R本政府宣布训柴,位于F島的核電站,受9級(jí)特大地震影響缰儿,放射性物質(zhì)發(fā)生泄漏畦粮。R本人自食惡果不足惜散址,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,075評(píng)論 3 327
  • 文/蒙蒙 一乖阵、第九天 我趴在偏房一處隱蔽的房頂上張望宣赔。 院中可真熱鬧,春花似錦瞪浸、人聲如沸儒将。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,705評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽钩蚊。三九已至,卻和暖如春蹈矮,著一層夾襖步出監(jiān)牢的瞬間砰逻,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,848評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工泛鸟, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蝠咆,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,831評(píng)論 2 370
  • 正文 我出身青樓北滥,卻偏偏與公主長(zhǎng)得像刚操,于是被迫代替她去往敵國(guó)和親皆警。 傳聞我的和親對(duì)象是個(gè)殘疾皇子苏研,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,678評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 0. 寫在前面 當(dāng)你開始工作時(shí),你不是在給你自己寫代碼脊另,而是為后來人寫代碼济赎。 —— Nichloas C. Zak...
    康斌閱讀 5,321評(píng)論 1 42
  • 特別說明鉴逞,為便于查閱,文章轉(zhuǎn)自https://github.com/getify/You-Dont-Know-JS...
    殺破狼real閱讀 467評(píng)論 0 0
  • 前言 先說明我并沒有要大家都來不加分號(hào),而是回答"為什么可以不加分號(hào)"豁遭,或是"為何分號(hào)是選項(xiàng)可有可無叭喜?",或是"分...
    小白_pk閱讀 3,673評(píng)論 1 3
  • 官方中文版原文鏈接 感謝社區(qū)中各位的大力支持蓖谢,譯者再次奉上一點(diǎn)點(diǎn)福利:阿里云產(chǎn)品券捂蕴,享受所有官網(wǎng)優(yōu)惠,并抽取幸運(yùn)大...
    HetfieldJoe閱讀 772評(píng)論 2 2
  • 情人節(jié)闪幽,年年過啥辨。 昨天老頭說:“今年情人節(jié)又到了”。 “那你送我什么禮物呀”我漫不經(jīng)心問盯腌。 “情人節(jié)溉知,是跟情人過,...
    閑人不二閱讀 1,484評(píng)論 20 25