印象中,JavaScript跟C、C#一樣,可以在程式碼段落中任意插入空白、換行而維持相同語意,屬於Free-Form Language的一員。

雖然排成這樣沒什麼道理,但以下JavaScript可以執行無誤:

        function calc(a, b) {
            var c = (a
                + b
                ) / 2
            ;
            return c;
        }
        alert(calc(5, 4));

手邊有段程式,在完成初步測試後花了點時間重新檢視程式碼,進行一些調整美化,在某個function中,由於return傳回的字串有點長,為了讓排版更好看一些,我改成以下寫法:

        function getSomething() {
            // ... blah blah ...
            return
            "line1 blah blah blah blah blah" +
            "line2 blah blah blah blah blah" +
            "line3 blah blah blah blah blah";
        }

改完後重新測試程式,晴天霹靂! 原本可以跑的程式壞掉了!!

由於這波程式微調的地方不少,花了好些時間才抓出問題出在原本return "line1 blah..."被改成return接換行,下一行才放"line1 blah..."。

經過研究,得知這個雷人陷阱有個專業術語叫Automatic Semicolon Insertion (ASI),JavaScript引擎會自動在以下指令後方加上分號";": [參考]

  • empty statement
  • var statement
  • expression statement
  • do-while statement
  • continue statement
  • break statement
  • return statement
  • throw statement

ASI跟return結合在一起,最為惡名昭彰、傷人無數... 網路上可以找到很多相關文章。簡單來說,前述的doSomething會程式會被解析成:

        function getSomething() {
            // ... blah blah ...
            return;
            "line1 blah blah blah blah blah" +
            "line2 blah blah blah blah blah" +
            "line3 blah blah blah blah blah";
        }

於是doSomething()傳回undefined,導致不正常的結果。

而ASI的特性,只有JavaScript有,return後方換行再寫,在C#、C、Java上都不會有問題,無怪乎許多程式老鳥也會中箭,在調整JavaScript程式碼排版時,宜多加留意!


Comments

# by Huang47

建議跑 linter, jslint or jshint

Post a comment