好吧,首先我應該問一下這是否與瀏覽器有關。 html
我已經讀到,若是找到了無效的令牌,可是代碼段在該無效令牌以前一直有效,若是在該令牌以前加了換行符,則在該令牌以前插入一個分號。 正則表達式
可是,引用由分號插入引發的錯誤的常見示例是: 瀏覽器
return _a+b;
..彷佛不遵循此規則,由於_a是有效令牌。 ide
另外一方面,分解呼叫鏈能夠按預期工做: 編碼
$('#myButton') .click(function(){alert("Hello!")});
是否有人對規則有更深刻的描述? spa
首先,您應該知道哪些語句受自動分號插入(爲簡潔起見也稱爲ASI)的影響: 設計
var
陳述 do-while
聲明 continue
聲明 break
聲明 return
聲明 throw
聲明 有關ASI的具體規則,請參見規範§11.9.1自動分號插入規則 code
描述了三種狀況: htm
當遇到語法不容許的標記( LineTerminator
或}
)時,若是出現如下狀況,則會在該標記前插入分號: ip
LineTerminator
與先前的令牌分隔。 }
例如 :
{ 1 2 } 3
轉化爲
{ 1 ;2 ;} 3;
NumericLiteral
1
知足第一個條件,如下標記是行終止符。
2
知足第二個條件,如下標記爲}
。
當遇到令牌輸入流的末尾而且解析器沒法將輸入令牌流做爲單個完整程序解析時,則分號會自動插入到輸入流的末尾。
例如 :
a = b ++c
轉換爲:
a = b; ++c;
若是某種語法的生產容許使用令牌,但這種生產是受限生產 ,則會在受限令牌以前自動插入分號。
限量生產:
UpdateExpression : LeftHandSideExpression [no LineTerminator here] ++ LeftHandSideExpression [no LineTerminator here] -- ContinueStatement : continue ; continue [no LineTerminator here] LabelIdentifier ; BreakStatement : break ; break [no LineTerminator here] LabelIdentifier ; ReturnStatement : return ; return [no LineTerminator here] Expression ; ThrowStatement : throw [no LineTerminator here] Expression ; ArrowFunction : ArrowParameters [no LineTerminator here] => ConciseBody YieldExpression : yield [no LineTerminator here] * AssignmentExpression yield [no LineTerminator here] AssignmentExpression
經典示例,帶有ReturnStatement
:
return "something";
轉化爲
return; "something";
直接來自ECMA-262,第五版ECMAScript規範 :
7.9.1自動分號插入規則
分號插入有三個基本規則:
- 當從左到右解析程序時,遇到語法產生的任何形式都不容許的令牌(稱爲冒犯令牌 )時,若是如下一項或多項操做,則在冒犯令牌以前會自動插入分號條件爲真:
- 至少有一個
LineTerminator
將有問題的令牌與先前的令牌分開。- 使人討厭的令牌是} 。
- 當從左到右解析程序時,遇到令牌輸入流的末尾而且解析器沒法將輸入令牌流解析爲單個完整的ECMAScript
Program
,則分號將自動插入到末尾。輸入流。- 當從左向右解析程序時,遇到某種語法的某種生產所容許的令牌,可是該生產是受限制的生產,而且該令牌將成爲緊隨註解以後的終端或非終端的第一個令牌受限生產中的「 [此處沒有
LineTerminator
] 」(所以,此類令牌稱爲受限令牌),而且受限令牌與上一個令牌之間由至少一個LineTerminator分隔,而後在受限令牌以前自動插入分號。可是,上述規則還有一個額外的優先條件:若是分號隨後將被解析爲空語句,或者該分號成爲for語句的標頭中的兩個分號之一,則永遠不會自動插入分號。 12.6.3)。
我沒法很好地理解規範中的這3條規則-但願能用更簡單的英語來表達-可是這是我從JavaScript中收集的:《權威指南》第6版,大衛·弗拉納根(David Flanagan),奧萊利(O'Reilly),2011年:
引用:
JavaScript不會將每一個換行符都視爲分號:一般,只有在沒有分號才能解析代碼的狀況下,纔將換行符視爲分號。
另外一個報價:對於代碼
var a a = 3 console.log(a)
JavaScript不會將第二個換行符視爲分號,由於它能夠繼續解析較長的語句a = 3;
和:
JavaScript不能將第二行解釋爲第一行語句的延續時,將換行符解釋爲分號的通常規則有兩個例外。 第一個異常涉及return,break和Continue語句
...若是在這些單詞中的任何一個以後出現換行符,則JavaScript始終會將該換行符解釋爲分號。
...第二個例外涉及++和-運算符...若是要將這些運算符中的任何一個用做後綴運算符,則它們必須與它們所適用的表達式出如今同一行。 不然,換行符將被視爲分號,而++或-將被解析爲應用於後面代碼的前綴運算符。 考慮如下代碼,例如:
x ++ y
它被解析爲
x; ++y;
x; ++y;
,而不是x++; y
x++; y
因此我想簡化一下,這意味着:
通常而言,JavaScript會在可能的範圍內將其視爲代碼的延續-兩種狀況除外:(1)在某些關鍵字(如return
, break
, continue
和(2)在看到++
或--
以後)新行,而後將添加;
在上一行的末尾。
關於「只要有意義就將其視爲代碼的延續來進行處理」的部分令人感受像是正則表達式的貪婪匹配。
有了以上所述,這意味着return
行並return
,JavaScript解釋器將插入;
(再次引用:若是在這些單詞中的任何一個以後出現換行符[例如return
] ... JavaScript始終會將該換行符解釋爲分號)
因爲這個緣由,
return { foo: 1 }
將沒法正常工做,由於JavaScript解釋器會將其視爲:
return; // returning nothing { foo: 1 }
return
後必須沒有換行符:
return { foo: 1 }
使其正常工做。 而且您能夠插入;
若是您要遵循使用a的規則;
在任何聲明以後:
return { foo: 1 };
我發現對JavaScript的自動分號插入的最上下文的描述來自一本有關製做解釋器的書。
JavaScript的「自動分號插入」規則很奇怪。 在其餘語言假設大多數換行符有意義的狀況下,而在多行語句中僅應忽略少數幾種,JS則相反。 除非遇到解析錯誤,不然它將全部換行符視爲無心義的空格。 若是是這樣,它將返回並嘗試將前一個換行符轉換爲分號以獲取語法上有效的內容。
他繼續描述它,就像您會編碼氣味同樣 。
若是我詳細瞭解它的工做原理,那麼本設計說明將變成一個設計思路,更不用說全部的各類壞方法了。 一團糟。 我知道JavaScript是惟一的一種語言,儘管在理論上可讓您忽略它們,但許多樣式指南在每一個語句後都須要顯式分號。
關於分號插入和var語句,請注意在使用var時要忘記逗號,但要跨多行。 昨天有人在個人代碼中找到了這個:
var srcRecords = src.records srcIds = [];
它運行了,但結果是srcIds聲明/賦值是全局的,由於因爲自動分號插入致使該語句被視爲完成,所以再也不應用前一行上帶有var的本地聲明。