不為人知的JavaScript自動分號插入機制(ASI)
楔子
之前一直寫C,寫了一段時間JavaScript之後一直很很好奇一個東西。在C和Java等語言裡面,大括號的使用一般都是類似這樣的
int main(args[])
{
return 0;
}
- 1
- 2
- 3
- 4
而到JavaScript裡面則是這樣寫
function main(args){
alert("hello");
return 0;
}
- 1
- 2
- 3
- 4
起始的大括號不獨佔一行了,覺得很疑惑,查了一些資料才知道,這是和JavaScript一個自動修復機制有關係,它總是希望通過自動插入分號來修正有缺損的程式,雖然我不知道這有什麼用。
自動插入分號機制
在《JavaScript語言精粹》這本書裡,這個機制被劃入到了JavaScript的毒瘤裡面,與之並列的前面的全域性變數。
有些時候,不合時宜地插入分號,會在例如return語句裡面導致嚴重的後果。
如果一個return語句要正確返回一個值,這個值的表示式的開始部分必須和return位於同一行。
我們來看下面這個例子
return
{
status:true;
}
- 1
- 2
- 3
- 4
看起來這是要返回一個包含物件,但是萬惡的自動插入分號處理後,返回值變成了undefined
,而且不會報任何的錯誤和警告。
如果我們把大括號這樣處理的話就能避免這個問題
return{
status:true;
};
- 1
- 2
- 3
自動插入分號的詳細規則
在es5標準中定義了自動分號插入規則,包括以下三個基本規則加上兩個前置條件。
前置條件
1.如果插入分號後解析結果是空語句,那麼不會自動插入分號。
例子:
if(i>j)
else k=l
- 1
- 2
這種情況下,if後面else前面是被解析為空語句,所以不加分號
2.如果插入分號後,它會成為for
語句頭部的兩個分號之一,那麼也不會插入分號
例如:
for(a;b
)
- 1
- 2
這種情況下,雖然分行了,但是不會被插入分號。
基本規則
從左向右解析程式的時候,當遇到一個不符合任何語法產生式的token
也就是違規標記的時候,那麼只要滿足下列條件之一,就會在哪個標記之前自動插入一個分號
1、前一個標記和這個違規標記之前至少存在一個行終止符
2、違規的標記是 }
舉個例子
{1
2}3
{1
;2;}3
- 1
- 2
- 3
- 4
在第一行和第二行的1、2不符合任何產生式,且它們之間有一個行終止符,所以會在數字2之前加分號,在第二行2後面也需要加一個分號,因為後面的違規標記是一個}
左到右解析程式,tokens 輸入流已經結束,當解析器無法將輸入 token 流解析成單個完整 ECMAScript 程式 ,那麼就在輸入流的結束位置自動插入分號。
對於受限產生式,也就是下面的5個,我們把產生式 後面的 token 叫做受限 token,如果在 token 和 受限 token 間存在了至少一個行終止符,那麼會在受限 token 前自動加上 token。
受限的產生式只限如下5個:
字尾表示式、continue語句、break語句、return語句、throw語句
如何預防這個毒瘤
1、字尾運算子 ++
或 --
和它的運算元應該出現在同一行。
2、return
或throw
語句的表示式開始位置應該和 return
或 throw
token 同一行。
3、break
或 continue
語句的標示符應該和 break
或continue
token 同一行。
最重要的還是多加分號
來自leviscar的小貼士
為啥只執行函式前面要加分號?
例如我之前看到的zepto.js的原始碼開頭
;(function(undefined) {
if (String.prototype.trim === undefined) // fix for iOS 3.2
String.prototype.trim = function() {
return this.replace(/^s+|s+$/g, ``)
}
- 1
- 2
- 3
- 4
- 5
主要是應對程式碼合併壓縮時,由於缺少分號;帶來的錯誤。知道了上面的規則,在 ( 開頭的行前加分號就可以避免錯誤了。
相關文章
- JavaScript到底應不應該加分號?JavaScript自動插入分號規則詳解JavaScript
- 鮮為人知的JavaScript功能JavaScript
- 不為人知的 Linus 大神
- Qt 自動連線機制訊號與槽QT
- 英特爾不為人知的 B 面
- 不為人知的easy-mock-cliMock
- opencv介面那些不為人知的事!OpenCV
- Android 8.0/9.0 wifi 自動連線評分機制AndroidWiFi
- JetBrains 裡不為人知的祕密(6)AI
- vue一些不為人知的用法Vue
- 走程式序員:那些不為人知的辛酸
- HTTP 的前世今生,那些不為人知的祕密HTTP
- 探索JavaScript的this機制JavaScript
- 二級指標與ARC不為人知的特性指標
- JetBrains 裡不為人知的祕密(4)--工具篇AI
- JavaScript的垃圾回收機制JavaScript
- JavaScript的垃圾收集機制JavaScript
- array_diff_uassoc 那些不為人知的一面
- 帶你瞭解 MySQL Binlog 不為人知的祕密MySql
- 谷歌創始人兼CEO拉里·佩奇不為人知的故事谷歌
- 自動化機器人的興起機器人
- GPT-3的不為人知的故事是OpenAI的轉型GPTOpenAI
- mybase 自動插入很多空行的問題
- 談談JavaScript中的this機制JavaScript
- 曝不為人知的十大行業內幕行業
- 網路安全“慣犯”,有哪些不為人知的祕密?
- [譯]震驚!RxJava 5 個不為人知的小祕密RxJava
- 軟體開發中的10大不為人知的真相
- 機器人使機床自動化機器人
- linux 訊號機制Linux
- 為什麼使用自注意力機制?
- css實現強制不換行/自動換行/強制換行CSS
- JavaScript執行緒機制與事件機制JavaScript執行緒事件
- Javascript 執行機制JavaScript
- JavaScript執行機制JavaScript
- Javascript非同步機制JavaScript非同步
- javascript 垃圾回收機制JavaScript
- 3分鐘看懂Python後端必須知道的Django的訊號機制!Python後端Django