用JSLint精煉提升JavaScript程式碼

jobbole發表於2012-10-31

  由於移動應用的盛行和HTML5的廣泛運用,JavaScript正越來越流行。JavaScript受歡迎的部分原因是因為它的靈活便捷,你可以快速上手,它不需要重量級的開發環境,也不需要第三方應用支援,只要你開啟一個文字編輯器,然後儲存,最後通過網頁瀏覽器執行即可。

  但是,對於新手而言,使用JavaScript處處存在陷阱。在一段複雜的指令碼中,JavaScript語言的延展性常常引起怪異的bug。例如,未宣告的區域性變數可能會不知不覺修改全域性變數。

  現在,開啟JSLint網站,正如其網站所言,它是“JavaScript程式碼質量工具”。JSLint的作者是Douglas Crockford,因其對JavaScript(ECMAScript)和JSON的貢獻而著名。

  (譯註:Douglas Crockford是 web領域技術權威之一,他是JSON、JSLint、JSMin和ADSafe的創造者,也是名著《JavaScript: The Good Parts》(中文版《JavaScript語言精粹 》)的作者。撰寫了許多廣為流傳、影響深遠的技術文章,包括“JavaScript:世界上最被誤解的語言”。)

  JSLint幫助JavaScript程式設計師在程式設計過程中遵循一定的編碼規範。JSLint是以基於嚴格模式(Strict Mode)為前提,參考第5版ECMAScript標準。與一般模式相比,嚴格模式下你的程式碼需要按照更嚴格的規則執行。

  (譯註:對嚴格模式不瞭解的童鞋,可以參考這兩篇文章《ECMAScript 5.1簡介》《是時候使用JavaScript嚴謹模式(Strict Mode)提升團隊開發效率》)

  使用JSLint

  我們來用JSLint執行一個示例。寫一個簡單的jQuery外掛,通過prefix顯示msg接收的資訊,如果傳給type的值為false則不顯示prefix。

(function ($) {
    $.fn.loading = function(msg, type, cssClass){
        var prefixes = {
            warning: 'Warning: ' + msg,
            error: 'Error: ' + msg,
            info: 'Info: ' + msg,
            warning: 'Caution: ' + msg,
        };
        if (type) {
            concatMsg = prefixes[type];
        } else {
            concatMsg = msg;
        }
        $(this).each(function()  {
            var tis = $(this)
            if (msg == false) {
                tis.html('');
            } else {
                tis.html(concatMsg);
            }
        });
     }
})(jQuery);

  儘管這段程式碼作為jQuery的外掛執行還算正常,但當你用Firefox或Chrome執行時,會發現有幾處明顯的錯誤,以及一些不易察覺的問題。與其耗費腦力解決這些問題,不如通過JSLint來幫助我們。將上面這段程式碼拷貝至JSLint網站的文字框內,然後點選”JSLint”按鈕,程式碼建議和錯誤提示會出現在下方。

  JSLint指出的第一個錯誤是:丟失“use strict”宣告。這個錯誤表示該函式未在嚴格模式下執行。為糾正該錯誤,我們在函式主體的頭部,新增“use strict”語句以啟動嚴格模式。

'use strict';

  加入嚴格模式宣告語句後,再次點選“JSLint”按鈕,提示丟失“use strict”的錯誤資訊將消失。現在,我們可以繼續看下一個錯誤。接下來的這個錯誤是關於空格的問題,鑑於它不能算個真正的錯誤,我們可以放心地忽略它。

  你可以將頁面最下方的“messy white space”選項改為true,這樣你就可以保留function關鍵字後不留空格的寫法。但是現在,我們保留“messy white space”選項的default屬性,因為這個功能也會幫助我們檢查其他空格問題,這個我們之後再說。

  同樣需要注意的是,雖然JSLint指出的第二個和第三個錯誤指向同一行程式碼,但錯誤點並不一樣。後者JSLint建議在右括號“)”和左大括號“{”之間空一格,現在我們糾正下這個錯誤。

  插入空格後,再次點選“JSLint”按鈕,下一個錯誤出現在第8行,第39個字元處。prefixes物件包含了兩個一模一樣的warning屬性,將第二個warning修改為caution。

  這次就不再點選“JSLint”按鈕,直接看下一個錯誤吧。定義物件的程式碼塊的最後多了一個逗號。像這類錯誤,Chrome和Firefox這些瀏覽器也許會忽略,但IE就不會那麼友好了,所以我們把這個逗號移除掉。

  之後的兩個錯誤指向未定義的變數concatMsg。如果一個變數在當前作用域中沒有被定義,JavaScript就會全域性查詢看是否有在別處定義過。若這時你還引入了外部程式碼,並碰巧在全域性中定義過該變數,那麼一旦出錯,你很有可能要抓破頭皮,費盡心力地尋找bug原因。所幸有了JSLint,我們可以將這類錯誤扼殺在搖籃中。

  現在糾正這個錯誤,並重構程式碼。因為concatMsg的預設值為msg,所以我們可以將msg先賦給它,待需要時再修改。如下所示,關於concatMsg的程式碼為:

var concatMsg = msg;
if (type) {
    concatMsg = prefixes[type];
}

  繼續往下,有一個與之前類似的空格問題,糾正它。緊接著,JSLint指出丟失了一個分號(如下圖所示)。JSLint會假設沒有分號結尾的命令列永遠不會被終止。所以,當下面出現if時,JSLint認為這裡應該有個分號。儘管根據語言規範,結束的分號可有可無,但是加上它是一個良好的習慣。因為這類不良程式碼在大專案協作中很容易引起莫名的bug。所以平常編碼過程中,應順手避免此類問題。

  接下來又是一個很好的錯誤例子。JavaScript中,有‘相等’(==)和嚴格的‘相等’(===)比較。在這段案例程式碼中,如果不採用嚴格‘相等’比較,那麼不管msg為空字串還是false值,if內都為true。所以,這裡我們採用嚴格‘相等’比較。

  好了,讓我們再次點選“JSLint”按鈕吧。如下圖所示,錯誤出現在第10行,JSLint認為合併變數宣告也是一個良好的編碼規範。儘管concatMsg變數的宣告緊隨prefixes之後,但JSLint認為用逗號隔開,在一個命令語句中完成變數宣告更好。

  下一個錯誤則又是關於格式的問題。咋一看,不就是多空了一格嘛,實在是太雞毛蒜皮了。但是,如果在大量的指令碼中,這種縮排問題搞不好也會引起難以發現的bug。所以,為了程式碼的統一性,我們還是往前移一格吧。

  下一個問題又和之前遇到的類似,但形式不一樣。JavaScript的函式也可歸屬為變數,所以和其他變數賦值語句一樣,JSLint希望在末尾加個分號。

  最後,如下所示,有兩個錯誤出現在最後一行。第一個問題,JSLint建議將閉括號移至jQuery之後,因為這樣不會使閉包函式定義產生歧義。第二個問題,JSLint認為jQuery變數不存在。但事實上你可能在實際頁面中已引入了jQuery檔案,所以我們可以在頁面最下面的文字框內輸入“jQuery”來解決這個問題(譯者:JSLint Directive上面的文字框)。

  再次執行JSLint,它提示該函式需要接收三個引數。但是在本示例中,我們從未使用過第三個引數。因此,此處我們有兩種方法解決這個問題。第一種,刪除第三個引數。第二種,將下方的“unused parameters”項改為true。如果你確實是因為某些原因需要保留這個引數,則用第二種方法。

  好了,用JSLint改進後的程式碼如下所示:

(function ($) {
    'use strict';
    $.fn.loading = function (msg, type, cssClass) {
        var prefixes = {
            warning: 'Warning: ' + msg,
            error: 'Error: ' + msg,
            info: 'Info: ' + msg,
            caution: 'Caution: ' + msg
        }, concatMsg = msg;
        if (type) {
            concatMsg = prefixes[type];
        }
        $(this).each(function () {
            var tis = $(this);
            if (msg === false) {
                tis.html('');
            } else {
                tis.html(concatMsg);
            }
        });
    };
}(jQuery));

  JSLint 指令

  你可以通過JSLint指令在你的原始碼中直接定義JSLint變數。這樣,你就不用在頁面上來回操作。如下示例,註釋中定義了jQuery全域性變數,並將“unparam”設為true。

/*global jQuery*/
/*jslint unparam: true */
(function ($) {
    ‘use strict’;
…
}(jQuery));

  總結

  在這個簡短的例子中,JSLint指出了一些明顯的和一些容易忽視的錯誤。在實際執行程式碼之前,通過JSLint幫我們查詢一些錯誤可以有效的提高我們的開發效率和程式碼質量。如果你真的是認真地想寫出優質的程式碼,那麼在放到伺服器上執行之前先用JSLint檢查一遍吧。JSLint還提供一個獨立的JS檔案版本,所以你也可以把它下載下來線上下執行!

  譯者:

  嚴格模式並不是所有的瀏覽器都支援,這是一個瀏覽器支援統計表。網頁前端可能暫時(甚至很長時間內)還不能遵循嚴格模式,但是在移動開發中顯然採用嚴格模式更佳。不管目前是否能用上,我覺得前端工程師們都應該利用這些工具幫助自己養成良好的編碼習慣,好的習慣會讓你受益匪淺,在這裡略矯情略誇張的引用一下電影《鐵娘子》中的一句話:Watch your habits, for they become your character

  英文原文:Using JSLint to Refine Your Code,編譯:伯樂線上 - 胡蓉

相關文章