花點時間搞清楚JS中的分號規則吧~~~無論你喜歡結尾帶分號或省略分號的模式javascript
分號通常容許出如今大部分語句(statement)的末尾,好比 do-while statement , var statements, expression statements , continue , return , break statement, throw, debugger 等html
栗子:java
do Statement while ( Expression ) ; 4+4; f(); debugger;
僅有一個分號 ; 能夠表示空語句——在JS中合法,好比 ;;;
可解析爲三個空語句(empty statement)node
空語句可用於輔助產生語法合法的解析結果,如:正則表達式
while(1);
若是沒有末尾的分號,將會產生解析錯誤 —— 條件循環後必須跟隨一個語句express
分號還會出如今 for 循環 for ( Expression ; Expression ; Expression ) Statement
中ide
最後,分號還會出如今 字符串 或 正則表達式中 —— 表示分號自己函數
有些場景下分號能夠省略,解析器在解析語句時會根據須要自動插入分號,大概流程能夠這樣理解:翻譯
書寫省略 => 解析器解析時發現缺乏時會沒法正確解析 => 自動添加分號debug
so 須要明確能自動插入分號的場景,並明確不會自動插入分號且會引發解析錯誤的狀況
規則1:當下一個 token (offending token) 和當前解析的 token (previous token) 沒法組成合法語句,且知足如下一個或多個條件時,將會在 offending token 前插入一個分號:
還要考慮一種優先級更高的條件:若是插入的分號會被解析爲一個空語句,或是 for 語句的頭部兩個分號之一,這時不會插入分號(除了 do-while 語句的終止分號外)
規則2:當解析到達源代碼文件 (input stream) 的末尾時,將自動添加一個分號標識解析結束
規則3:符合 restricted production
語法的語句 —— 比較難翻譯,看不懂的能夠直接看栗子,這種狀況主要描述的是:不該該出現換行符的地方出現換行符致使插入分號引發原語句含義變化
同時知足如下條件,將在 offending token 前自動插入一個分號:
其中 restricted production 包括且只有如下:
UpdateExpression[Yield, Await]: LeftHandSideExpression[?Yield, ?Await] [no LineTerminator here] ++ LeftHandSideExpression[?Yield, ?Await] [no LineTerminator here] -- ContinueStatement[Yield, Await]: continue; continue [no LineTerminator here] LabelIdentifier[?Yield, ?Await]; BreakStatement[Yield, Await]: break; break [no LineTerminator here] LabelIdentifier[?Yield, ?Await]; ReturnStatement[Yield, Await]: return; return [no LineTerminator here] Expression [+In, ?Yield, ?Await]; ThrowStatement[Yield, Await]: throw [no LineTerminator here] Expression [+In, ?Yield, ?Await]; ArrowFunction[In, Yield, Await]: ArrowParameters[?Yield, ?Await] [no LineTerminator here] => ConciseBody[?In] YieldExpression[In, Await]: yield [no LineTerminator here] * AssignmentExpression[?In, +Yield, ?Await] yield [no LineTerminator here] AssignmentExpression[?In, +Yield, ?Await]
簡單總結:
a++
語句時,變量和 ++
必須在同一行,不然會在 ++
前插入分號致使語義不一樣return
throw
yield
continue
break
後若是緊跟着換行,將會自動添加分號符合預期狀況
// 至關於 42;"hello" 42 "hello" // offending token 是 } if(x){y()} // previous token 是 ) 且插入分號是 do while 語句的結束 var a = 1 do {a++} while(a<100) console.log(a) // 不會解析成 b++ 由於 b和++之間存在換行符,會在 b 以後自動插入分號 a = b ++c
可能不符合預期的狀況
const hey = 'hey' const you = 'hey' const heyYou = hey + ' ' + you ['h', 'e', 'y'].forEach((letter) => console.log(letter))
會收到錯誤 Uncaught TypeError: Cannot read property 'forEach' of undefined
, 由於 you 和 ['h', 'e', 'y'] 的鏈接能命中合法語法,故它們之間不會自動插入分號 —— 與預期不一致,JS嘗試將代碼解析爲:
const hey = 'hey'; const you = 'hey'; const heyYou = hey + ' ' + you['h', 'e', 'y'].forEach((letter) => console.log(letter))
再看一種狀況:
const a = 1 const b = 2 const c = a + b (a + b).toString()
會引起 TypeError: b is not a function
報錯,由於會被解釋爲:
const a = 1 const b = 2 const c = a + b(a + b).toString()
除了 do while 語句外,不會有插入分號做爲空語句的其餘狀況,或做爲 for 語句頭部的兩個必要分號 :
if (a > b) else c = d for (a; b )
以上均不是合法的 JS 語句,而且會引發報錯
故如下栗子中的每個分號都不能省略!!
// for循環沒有循環體的狀況,每個分號都不能省略 for (node=getNode(); node.parent; node=node.parent) ;
再看一個帶詳細註釋的例子:
var // 這一行不會插入分號 ,由於 下一行的代碼不會破壞當前行的代碼 a = 1 // 這一行會插入分號 let b = 2 // 再好比這種狀況,你的原意多是定義 `a` 變量,再執行 `(a + 3).toString()`, // 可是其實 JavaScript 解析器解析成了,`var a = 2(a + 3).toString()`, // 這時會拋出錯誤 Uncaught TypeError: 2 is not a function var a = 2 (a + 3).toString() // 同理,下面的代碼會被解釋爲 `a = b(function(){...})()` a = b (function(){ ... })()
以上都是未能命中規則1而未插入分號致使解析與預期不符合的狀況
看一個基於規則3的例子:
(() => { return { color: 'white' } })()
預期是返回一個包含 color 屬性的對象,但事實上 return 後會被插入一個分號,而致使最終返回 undefined,能夠經過在 return 後馬上放置花括號 { :
(() => { return { color: 'white' } })()
return
break
throw
continue
語句,若是須要跟隨參數或表達式,把它添加到和這些語句同一行,針對 return
返回內容較多的狀況 (大對象,柯里化調用,多行字符串等),能夠參考規則1,避免命中該規則而引發非預期的分號插入,好比:return obj.method('abc') .method('xyz') .method('pqr') return "a long string\n" + "continued across\n" + "several lines" totalArea = rect_a.height * rect_a.width + rect_b.height * rect_b.width + circ.radius * circ.radius * Math.PI
固然大部分工程化狀況下,咱們最終會配合Eslint使用帶分號或省略分號規範~~~
參考:
ECMAScript規範
http://ecma-international.org/ecma-262/9.0/index.html#sec-automatic-semicolon-insertion
JavaScript 中的分號(;) – JavaScript 徹底手冊(2018版)(翻譯版)
https://www.html.cn/archives/10061
JavaScript Semicolon Insertion
Everything you need to know
http://inimino.org/~inimino/blog/javascript_semicolons