前言
相信從事過C#和Java的大家都知道分號是用作斷句(EOS,end of statement)的,而且必須加分號,否則編譯就不通過了。但JavaScript由於存在ASI機制,因此允許我們省略分號。ASI機制不是說在解析過程中解析器自動把分號添加到代碼中,而是說解析器除了分號還會以換行為基礎按一定的規則作為斷句的依據,從而保證解析的正確性。
規范理論
es5 標准定義了自動分號插入規則,包括以下三個基本規則加兩個前置條件:
前置條件
1、如果插入分號後解析結果是空語句,那麼不會自動插入分號。
例子:(空語句,else
前不加分好)
if (a > b) else c = d
2、如果插入分號後它成為 for
語句頭部的兩個分號之一,那麼不會自動插入分號。
例子:(不會加分號)
for (a; b )
基本規則
左到右解析程序,當遇到一個不符合任何文法產生式的 token
(叫做 違規 token(offending token)),那麼只要滿足下面條件之一就在違規 token
前面自動插入分號。
1、至少一個 LineTerminator 分割了違規 token
和前一個 token
。
2、違規 token
是 }。
例子:(1、2不符合任何產生式,並且之間存在 LineTerminator,因此在違規 token 2前加了分好,2和}則是因為違規 token
是 }所以加了分號)
{ 1 2 } 3
{ 1 ;2 ;} 3;
左到右解析程序,tokens
輸入流已經結束,當解析器無法將輸入 token
流解析成單個完整 ECMAScript 程序 ,那麼就在輸入流的結束位置自動插入分號。
對於受限產生式,也就是下面的5個,我們把產生式 [no LineTerminator here]後面的 token
叫做受限 token
,如果在 token
和 受限 token
間存在了至少一個 LineTerminator,那麼會在受限 token
前自動加上 token
。
受限的產生式只限如下5個:
PostfixExpression :
LeftHandSideExpression [no LineTerminator here] ++ LeftHandSideExpression [no LineTerminator here] --
ContinueStatement :
continue [no LineTerminator here] Identifier;
BreakStatement :
break [no LineTerminator here] Identifier;
ReturnStatement :
return [no LineTerminator here] Expression;
ThrowStatement : throw [no LineTerminator here] Expression;
歸納
避免 ASI 帶來的問題
1、後綴運算符 ++ 或 -- 和它的操作數應該出現在同一行。
2、return
或 throw
語句的表達式開始位置應該和 return
或 throw token
同一行。
3、break
或 continue 語句的標示符應該和 break
或 continue token
同一行。
何時加分號
無分號黨(懶人黨)想要不加分號,那麼就需要知道什麼時候應該要加分號。網上的一篇文章歸納了 NO ASI 並且會出現錯誤的幾種情況,在這幾種情況下我們是要加分號的。下面是對應的描述:
在以 ([/+- 開頭的語句前加分號(由於正常寫法均不會出現以 .,*% 作為語句開頭,因此只需記住前面5個即可,你看能懶則懶哦)
不過這裡只考慮了換行的情況,其實 ASI 還存在不換行的情況,這就要根據標准裡的三條規則行事了!
知道了這點,其實我們就可以省略大部分的分號了。但是也不強求,因為這還是要根據個人習慣以及團隊風格走的。
小補充
為什麼自執行函數前要加分號?
主要是應對代碼合並壓縮時,由於缺少分號;帶來的錯誤。知道了上面的規則,在 ( 開頭的行前加分號就可以避免錯誤了。
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作能帶來一定的幫助,如果有疑問大家可以留言交流。