首頁  >  文章  >  web前端  >  Javascript分號規則的知識介紹(附範例)

Javascript分號規則的知識介紹(附範例)

不言
不言轉載
2019-03-25 14:21:032856瀏覽

這篇文章帶給大家的內容是關於Javascript分號規則的知識介紹(附範例),有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。

花點時間搞清楚JS中的分號規則吧~~~不管你喜歡結尾帶分號或省略分號的模式

分號允許的場景

#分號一般允許出現在大部分語句(statement)的結尾,例如do-while statement , var statements, expression statements , continue , return , break statement, throw, debugger 等

栗子:

#栗子:

do Statement while ( Expression ) ;

4+4;

f();

debugger;
只有一個分號; 可以表示空語句-在JS中合法,例如;;; 可解析為三個空語句(empty statement)

空語句可用於輔助產生語法合法的解析結果,如:

while(1);
如果沒有末尾的分號,將會產生解析錯誤- 條件循環後必須跟隨一個語句

分號還會出現在for 迴圈 for ( Expression ; Expression ; Expression ) Statement 中

最後,分號也會出現在字串或正規表示式中- 表示分號本身

分號可以省略的場景

有些場景下分號可以省略,解析器在解析語句時會根據需要自動插入分號,大概流程可以這樣理解:

書寫省略=> 解析器解析時發現缺少時會無法正確解析=> 自動加入分號

so 需要明確能自動插入​​分號的場景,並且明確不會自動插入分號且會造成解析錯誤的情況

規則1:當下一個token (offending token) 和目前解析的token (previous token) 無法組成合法語句,且滿足以下一個或多個條件時,將會在offending token 前插入一個分號:
  • offending token 和previous token 被至少一個換行符分割(LineTerminator),且分號插入的作用不是被解析為空語句(empty statement)
  • offending token 是}
  • previous token 是), 並且插入的分號將被解析為do-while語句的終止分號

還要考慮一種優先級更高的條件:如果插入的分號會被解析為一個空語句,或是for 語句的頭部兩個分號之一,這時不會插入分號(除了do-while 語句的終止分號外)

規則2:當解析到達原始碼檔案(input stream) 的結尾時,將自動新增一個分號標識解析結束

規則3:符合 restricted production 語法的語句- 比較難翻譯,看不懂的可以直接看栗子,這種情況主要描述的是:不應該出現換行符的地方出現換行符導致插入分號引起原語句含義變化

#同時滿足以下條件,將在offending token 前自動插入一個分號:
  • offending token 和previous token 組成合語法的restricted production 語句
  • offending token 出現於restricted production 語句描述中的[no LineTerminaator here] 部分( the token would be the first token for a terminal or nonterminal immediately following the annotation “[no LineTerminator here]” within the restricted production )
  • offending token 和previous token 之間至少存在一個換行符之間至少存在一個換行符(LineTerminator)##;

其中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 = &#39;hey&#39;
const you = &#39;hey&#39;
const heyYou = hey + &#39; &#39; + you

[&#39;h&#39;, &#39;e&#39;, &#39;y&#39;].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使用带分号或省略分号规范~~~

本篇文章到这里就已经全部结束了,更多其他精彩内容可以关注PHP中文网的JavaScript视频教程栏目!

以上是Javascript分號規則的知識介紹(附範例)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:segmentfault.com。如有侵權,請聯絡admin@php.cn刪除