天天看點

javascript成神之路(1):如何編寫高品質的js代碼一、如何書寫可維護性的代碼二、全局變量的問題三、忘記var作用的副作用四、通路全局對象五、for循環六、不擴充内置原型七、避免隐式類型轉換八、避免eval()九、編碼規範十、縮進十一、注釋十二、花括号{}

一、如何書寫可維護性的代碼

當出現bug的時候如果你能立馬修複它是最好的,此時解決問題的四路在你腦中還是很清晰的。否則,你轉移到其他任務或者bug是經過一定的時間才出現的,你忘了那個特定的代碼,一段時間後再去檢視這些代碼就 需要:

1.花時間學習和了解這個問題 2.化時間是了解應該解決的問題代碼

還有個問題,特别對于大的項目或是公司,修複bug的這位夥計不是寫代碼的那個人(且發現bug和修複bug的不是同一個人)。是以,必須降低了解代 碼花費的時間,無論是一段時間前你自己寫的代碼還是團隊中的其他成員寫的代碼。這關系到底線(營業收入)和開發人員的幸福,因為我們更應該去開發新的激動 人心的事物而不是花幾小時幾天的時間去維護遺留代碼。是以建立可維護性代碼是至關重要的,一般可維護性的代碼有以下幾個原則:

  • 可讀性
  • 一緻性
  • 可預測性
  • 看上去就像同一個人寫的
  • 已記錄

二、全局變量的問題

全局變量的問題在于,你的JavaScript應用程式和web頁面上的所有代碼都共享了這些全局變量,他們住在同一個全局命名空間,是以當程式的兩個不同部分定義同名但不同作用的全局變量的時候,命名沖突在所難免。web頁面包含不是該頁面開發者所寫的代碼也是比較常見的,例如:

  • 第三方的JavaScript庫
  • 廣告方的腳本代碼
  • 第三方使用者跟蹤和分析腳本代碼
  • 不同類型的小元件,标志和按鈕

例如說,該第三方腳本定義了一個全局變量,叫做A;接着,在你的函數中也定義一個名為A的全局變量。其結果就是後面的變量覆寫前面的,第三方腳本就一下子失效啦!而且很難debug出來。

是以:盡可能少的使用全局變量是很重要的,例如命名空間模式或是函數立即自動執行,但是要想讓全局變量少最重要的還是始終使用var來聲明變量。

三、忘記var作用的副作用

隐式全局變量和明确定義的全局變量間有些小的差異,就是通過delete操作符讓變量未定義的能力。具體如下:

  • 通過var建立的全局變量(任何函數之外的程式中建立)是不能被删除的。
  • 沒有通過var建立的隐式全局變量(無視是否在函數中建立)是能被删除的。

是以隐式全局變量并不是真正的全局變量,但它們是全局對象的屬性。屬性是可以通過delete操作符删除的,而變量是不能的,具體代碼我就不寫了。

四、通路全局對象

在浏覽器中,全局對象可以通過window屬性在代碼的任何位置通路(除非你做了些比較出格的事情,像是聲明了一個名為window的局部變量)。但是在其他環境下,這個友善的屬性可能被叫做其他什麼東西(甚至在程式中不可用)。如果你需要在沒有寫死的window辨別符下通路全局對象,你可以在任何層級的函數作用域中做如下操作:

var global = (function () { return this; }());

五、for循環

在for循環中,你可以循環取得數組或是數組類似對象的值,譬如arguments和HTMLCollection對象。通常的循環形式如下:

// 次佳的循環 for (var i = 0; i < myarray.length; i++) { // 使用myarray[i]做點什麼 }

這種形式的循環的不足在于每次循環的時候數組的長度都要去擷取下。這回降低你的代碼,尤其當myarray不是數組,而是一個HTMLCollection對象的時候。

六、不擴充内置原型

擴增構造函數的prototype屬性是個很強大的增加功能的方法,但有時候它太強大了。增加内置的構造函數原型(如Object(), Array(), 或Function())挺誘人的,但是這嚴重降低了可維護性,因為它讓你的代碼變得難以預測。使用你代碼的其他開發人員很可能更期望使用内置的 JavaScript方法來持續不斷地工作,而不是你另加的方法。另外,屬性添加到原型中,可能會導緻不使用hasOwnProperty屬性時在循環中顯示出來,這會造成混亂。

七、避免隐式類型轉換

JavaScript的變量在比較的時候會隐式類型轉換。這就是為什麼一些諸如:false == 0 或 “” == 0 傳回的結果是true。為避免引起混亂的隐含類型轉換,在你比較值和表達式類型的時候始終使用===和!==操作符。

var zero = 0; if (zero === false) { // 不執行,因為zero為0, 而不是false } // 反面示例 if (zero == false) { // 執行了... }

八、避免eval()

如果你現在的代碼中使用了eval(),記住該咒語“eval()是魔鬼”。此方法接受任意的字元串,并當作JavaScript代碼來處理。當有 問題的代碼是事先知道的(不是運作時确定的),沒有理由使用eval()。如果代碼是在運作時動态生成,有一個更好的方式不使用eval而達到同樣的目 标。例如,用方括号表示法來通路動态屬性會更好更簡單:

// 反面示例 var property = "name"; alert(eval("obj." + property)); // 更好的 var property = "name"; alert(obj[property]);

使用eval()也帶來了安全隐患,因為被執行的代碼(例如從網絡來)可能已被篡改。這是個很常見的反面教材,當處理Ajax請求得到的JSON 相應的時候。在這些情況下,最好使用JavaScript内置方法來解析JSON相應,以確定安全和有效。若浏覽器不支援JSON.parse(),你可 以使用來自JSON.org的庫。

同樣重要的是要記住,給setInterval(), setTimeout()和Function()構造函數傳遞字元串,大部分情況下,與使用eval()是類似的,是以要避免。在幕後,JavaScript仍需要評估和執行你給程式傳遞的字元串:

// 反面示例 setTimeout("myFunc()", 1000); setTimeout("myFunc(1, 2, 3)", 1000); // 更好的 setTimeout(myFunc, 1000); setTimeout(function () { myFunc(1, 2, 3); }, 1000);

使用新的Function()構造就類似于eval(),應小心接近。這可能是一個強大的構造,但往往被誤用。如果你絕對必須使用eval(),你 可以考慮使用new Function()代替。有一個小的潛在好處,因為在新Function()中作代碼評估是在局部函數作用域中運作,是以代碼中任何被評估的通過var 定義的變量都不會自動變成全局變量。另一種方法來阻止自動全局變量是封裝eval()調用到一個即時函數中。

考慮下面這個例子,這裡僅un作為全局變量污染了命名空間。

console.log(typeof un); // "undefined" console.log(typeof deux); // "undefined" console.log(typeof trois); // "undefined" var jsstring = "var un = 1; console.log(un);"; eval(jsstring); // logs "1" jsstring = "var deux = 2; console.log(deux);"; new Function(jsstring)(); // logs "2" jsstring = "var trois = 3; console.log(trois);"; (function () { eval(jsstring); }()); // logs "3" console.log(typeof un); // number console.log(typeof deux); // "undefined" console.log(typeof trois); // "undefined"

另一間eval()和Function構造不同的是eval()可以幹擾作用域鍊,而Function()更安分守己些。不管你在哪裡執行 Function(),它隻看到全局作用域。是以其能很好的避免本地變量污染。在下面這個例子中,eval()可以通路和修改它外部作用域中的變量,這是 Function做不來的(注意到使用Function和new Function是相同的)。

(function () { var local = 1; eval("local = 3; console.log(local)"); // logs "3" console.log(local); // logs "3" }()); (function () { var local = 1; Function("console.log(typeof local);")(); // logs undefined

九、編碼規範

建立和遵循編碼規範是很重要的,這讓你的代碼保持一緻性,可預測,更易于閱讀和了解。一個新的開發者加入這個團隊可以通讀規範,了解其它團隊成員書寫的代碼,更快上手幹活。

十、縮進

代碼沒有縮進基本上就不能讀了。唯一糟糕的事情就是不一緻的縮進,因為它看上去像是遵循了規範,但是可能一路上伴随着混亂和驚奇。重要的是規範地使用縮進。

十一、注釋

你必須注釋你的代碼,即使不會有其他人向你一樣接觸它。通常,當你深入研究一個問題,你會很清楚的知道這個代碼是幹嘛用的,但是,當你一周之後再回來看的時候,想必也要耗掉不少腦細胞去搞明白到底怎麼工作的。

很顯然,注釋不能走極端:每個單獨變量或是單獨一行。但是,你通常應該記錄所有的函數,它們的參數和傳回值,或是任何不尋常的技術和方法。要想到注 釋可以給你代碼未來的閱讀者以諸多提示;閱讀者需要的是(不要讀太多的東西)僅注釋和函數屬性名來了解你的代碼。例如,當你有五六行程式執行特定的任務, 如果你提供了一行代碼目的以及為什麼在這裡的描述的話,閱讀者就可以直接跳過這段細節。沒有硬性規定注釋代碼比,代碼的某些部分(如正規表達式)可能注釋 要比代碼多。

十二、花括号{}

花括号(亦稱大括号,下同)應總被使用,即使在它們為可選的時候。技術上将,在in或是for中如果語句僅一條,花括号是不需要的,但是你還是應該總是使用它們,這會讓代碼更有持續性和易于更新。

原文釋出時間:2018年01月06日

作者:

技術金三胖

本文來源:

開源中國

  如需轉載請聯系原作者

繼續閱讀