標籤:

js中return有什麼設計錯誤?

js語言精粹第96頁說,「{ 必須寫在每一行結尾而不是下一行,這樣會避免 return 設計錯誤。」

這裡的錯誤指的是什麼?


居然有幾個人在看= =。。

總而言之,是javascript有一個自動修復機制——在程序可能有缺陷的時候,自動插入分號補全。但這個機制很不靠譜,常常會掩蓋一些錯誤。

比如

return {
hello:"world";
};

正常的理解是返回一個字面量構成的對象。

如果寫成

return
{
hello:"world"
};
在自動補齊時就會變成
return;
{
hello:"world"
};

實際返回一個undefined,這種錯誤不會有任何提示

更多自動補齊的特徵請參考ECMAScript文檔

http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf

或中文版

ECMAScript5.1中文版


這是自動分號補齊 ( auto semicolon insertion,簡稱ASI ) 一個常見的坑。

在ASI的機制中有一類語句叫做restricted productions(不知道中文叫啥)。簡單來說,就是組成這類語句的兩個token當中不允許出現換行符
。如果在第一個token後面遇到了換行符,則判斷語句結束,插入分號。restricted productions包括:

  • return xxx (xxx是要返回的對象)

  • throw xxx(xxx是要拋出的錯誤對象)

  • break / continue xxx(xxx是循環的標籤)

  • 作為後綴的 ++ / --

其中前幾個關鍵詞還是挺容易記的,最後一條的原因是需要區分以下情況:

a
++
b

因為++/--既可以作為前綴又可以作為後綴,在這樣的情況下作為後綴解析會遇上換行符,所以只能作為b的前綴,自動插入分號後變成:

a; ++b;

回到原題,Douglas Crockford認為 { 應該寫在行尾,是為了避免換行符導致return直接返回undefined。

篇外:關於分號 ------------------------------------------------------------------------------------------------

很多人覺得ASI坑太多了所以提倡永遠手動加分號,這樣就不用費心去研究ASI的規則了。但事實上,即使永遠手動加分號,你依然會被restricted productions這條規則坑,因為它是在你不想要分號的地方給你插入分號。所以不管你喜不喜歡分號,都最好花點時間好好了解一下ASI的規則。而一旦你知道了ASI所有的坑,不寫分號其實是很簡單的。

ASI真正需要注意的坑只有兩個,restricted productions是其一,另一個就是當下一行開頭是 ( [ / 這三個字元之一的時候:

a = b
(function () { ... }())

會被解析成

a = b(function () {...}());

換言之,( ) 會被看做是在調用函數b。同理,[ ] 會被看做是在獲取b的屬性,而被斜杠坑的情況則要求更苛刻一些:

a = b
/Error/i.test(str) doSomething()

第二行的寫法本身比較少見,但也不是不可能。結果會被解析成:

a = b / Error / i.test(str) doSomething();

斜杠被解析成了除號!

要躲開這個坑,其實真的挺簡單,只要盡量別用這三個字元作為一行開頭就行了。事實上遇到比較多的也只有括弧開頭。真的避不開的話,可以在行頭手動加個分號:

a = b
;(function () { ... }())

額外的一點是在for循環聲明裡面的分號是永遠不能省的,ASI不會在for循環聲明中插分號,但一般正常人不會把for的聲明分三行寫吧...

每次我看到 「javascript分號坑很多,所以應該永遠加分號」 這樣的說法總是有些不屑的,因為永遠加分號並不是避免錯誤的辦法,搞懂ASI是怎麼回事才是。只要理解了這裡說的兩個坑,javascript里99%的分號都是不必要的。


js中除了function 後面一律都應該自己手動添加 ;

return中 樓上的那個問題 曾經是我一個血的教訓啊 return 後面千萬不要跟 換行(回車)


推薦閱讀:

leetcode之2sum丶3sum(closest)丶4sum演算法總結
sku 多維屬性狀態判斷演算法
靜態網站生成器是如何工作的
redux 入門介紹
這種線條是怎麼畫出來的?

TAG:JavaScript |