注:本文轉載自developerworks
簡介: JavaScript 程式語言作為最流行的客戶端指令碼語言,早已被眾多 Web 開發人員所熟悉。隨著 Web2.0 時代的到來和 Ajax 技術的廣泛應用,JavaScript 也逐漸吸引著更多的視線。工作中要求越多的是對 JavaScript 語言的深入學習,靈活運用,和對編碼質量的保證。
對於熟悉 C/C++ 或 Java 語言的工程師來說,JavaScript 顯得靈活,簡單易懂,對程式碼的格式的要求也相對鬆散。很容易學習,並運用到自己的程式碼中。也正因為這樣,JavaScript 的編碼規範也往往被輕視,開發過程中修修補補,最終也就演變成為後續維護人員的惡夢。軟體存在的長期價值直接與編碼的質量成比例。編碼規範能幫助我們降低程式設計中不必要的麻煩。而 JavaScript 程式碼是直接傳送給客戶瀏覽器的,直接與客戶見面,編碼的質量更應該受到關注。
本文淺談 JavaScript 程式設計中關於編碼規範的問題,分析其中緣由。希望引起更多 Web 開發人員對 JavaScript 編碼規範問題的關注和對軟體產品質量問題的重視。
前言
提及 C/C++ 和 Java 編碼規範,相信許多工程師並不生疏。但說到 JavaScript 語言的編碼規範,也許您會忍俊不禁。JavaScript 不是語法很靈活嗎?變數隨時用隨時可以宣告;語句結束符可以不要;字串和數字也可以相加;引數多一個少一個也不會報錯。沒錯,當您從 C/C++ 和 Java 嚴格的語法規定之下,轉向 JavaScript 語言,會覺得自由了很多,輕鬆了很多。語法鬆散是 JavaScript 重要的特徵。它靈活易懂,給開發人員帶來了很多方便,但如果編寫過程中不注意,程式碼的除錯成本和維護成本則會無形地增加。
JavaScript 編碼會隨應被直接傳送到客戶端的瀏覽器,程式碼規範不只是程式碼質量的保證,也影響到產品的長期信譽。希望 JavaScript 程式語言的規範問題也能同樣引起更多朋友的關注。
JavaScript 編碼規範建議
本文就 JavaScript 編碼過程中涉及的排版、命名、宣告、作用域、及一些特殊符號的使用等方面,根據個人在學習工作中的總結,給出自己的一些建議,並分析其中緣由,以供參考。
JavaScript 檔案引用
JavaScript 程式應該儘量放在 .js 的檔案中,需要呼叫的時候在 HTML 中以 < script src=”filename.js”> 的形式包含進來。JavaScript 程式碼若不是該 HTML 檔案所專用的,則應儘量避免在 HTML 檔案中直接編寫 JavaScript 程式碼。因為這樣會大大增加 HTML 檔案的大小,無益於程式碼的壓縮和快取的使用。
另外,< script src=”filename.js”> 標籤應儘量放在檔案的後面。這樣會降低因載入 JavaScript 程式碼而影響頁面中其它元件的載入時間。
程式碼排版
行長度
每行程式碼應小於 80 個字元。如果程式碼較長,應儘量選擇換行,下一行程式碼應縮排 8 個空格。這樣可以使程式碼排版整齊,減輕閱讀程式碼的疲勞感。換行縮排 8 個空格可以和程式碼段的縮排 4 個空格區分開,以增強程式碼的可閱讀性。
行結束
JavaScript 語句應該以分號結束。但大多數瀏覽器允許不寫分號,只要在本應是分號的地方有一個換行符就行。但是如果程式碼行較長需要換行的時候,有哪些注意事項呢?換行應選擇在操作符和標點符號之後,最好是在逗號’,’之後,而不要在變數名、字串、數字、或’)’ ‘]’ ‘++’ ‘–‘等符號之後換行。
這樣可以有效的防止拷貝、貼上而引起的錯誤,並可有效地增強程式碼的可閱讀性。請見清單 1,程式碼的輸出符合我們的期望。但就寫法而言,對 valueB 的賦值語句是在變數 valueA 之後進行的換行,這很容易被誤解為 valueB=ValueA,給閱讀造成障礙。而對 valueC 的複製語句是在’+’之後進行的換行,就容易理解的多。這也是本文所提倡的換行方式。
清單 1. 行結束的位置
1 |
< script language="javascript"> var valueA = 1; var valueB = valueA ///bad +1; var valueC = valueB + ///good valueA; alert(valueB); //output: valueB=2 alert(valueC);//output: valueC=3 < /script> |
縮排
關於縮排的問題,不只是 JavaScript,幾乎所有的語言編寫的時候,都會提及縮排的問題。縮排幾乎是程式碼編寫規範的第一課,是程式碼可閱讀性判斷的直接因素。
程式碼縮排的好處是不言而喻的,但是對於如何縮排,則沒有標準而言。最受歡迎的是方便使用 TAB 鍵縮排,也有些喜歡用 2 個、4 個、8 個空格進行縮排。這樣縮排風格不一,也同樣給程式碼的閱讀帶來障礙。
本文提倡用 4 個空格來進行縮排,並在同一產品中採用同一種縮排標準。不支援用 TAB 鍵進行縮排。這是因為直到現在還沒有統一的標準來定義 TAB 鍵所代替的空白大小,有些編輯器解析為 4 個空格大小,有些則解析為 8 個。因而用不同的編輯器檢視程式碼,可能造成格式混亂。當然 TAB 簡單易用,為解決這個問題,建議在設定開發環境時,將編輯器裡的 TAB 快捷鍵重新設定為 4 個空格。據瞭解 Eclipse, Vi, Nodepad++,Editplus, UltraEdit 等流行的編輯器,均提供了此功能。
註釋
程式碼中的註釋很重要,自然也是毋庸置疑的。通常我們會強調程式碼中註釋數量的多少,而輕視了對註釋質量的提高。編碼是及時新增註釋,會給後續程式碼的維護人員帶來很大的便利。但是如果註釋不注意更新,或者由於拷貝、貼上引起的錯誤的註釋,則會誤導閱讀人員,反而給閱讀帶來障礙。
除了註釋要 及時更新外,我們還應對註釋的內容要特別關注。註釋要儘量簡單、清晰明瞭,避免使用含混晦澀的語言,同時著重 註釋的意義,對不太直觀的部分進行註解。請見清單 2。
清單 2. 有意義的註釋
1 |
< script language="javascript"> //following section is used to initialize golbal variables (good) var valueA = 0; //initialize valueA to be sero (bad) var valueB = 1; ... //call f1 function after waiting for 50 seconds. (good) setTimeout(f1,50000); //set timeout to be 20s (copy error) ... < /script> |
這樣的註釋方式在 JavaScript 程式碼中經常見到。”initialize valueA to be sero” 這樣的註釋有什麼用呢?難道閱讀程式的工程師從”var valueA = 0;”複製語句中看不出來麼?”set timeout to be 20s”這條註釋,不只是因拷貝、貼上引起的時間大小的錯誤,同時也誤導了程式設計師對這條語句的理解。setTimeout() 函式的作用並非是設定函式執行的超時時間,而是等待一定時間後執行所呼叫的函式,害人匪淺呀。這樣的註釋內容寧可刪掉。
此外,JavaScript 的註釋有兩種”//” 和”/* …. */”,建議”//”用作程式碼行註釋,”/* …. */”形式用作對整個程式碼段的登出,或較正式的宣告中,如函式引數、功能、檔案功能等的描述中。
識別符號命名
JavaScript 中的識別符號的命名規則:
- 以字母、下劃線’_’或美元符號’$’開頭
- 允許名稱中包含字母,數字,下劃線’_’和美元符號’$’
- 區分大小寫
變數、引數、成員變數、函式等名稱均以小寫字母開頭,構造器的名稱以大寫字母開頭。下劃線’_’開頭的變數一般習慣於標識私有 / 區域性成員。而美元符號’$’開頭的變數習慣於標識系統相關,比如系統程式等。應避免用下劃線’_’或美元符號’$’來命名識別符號。儘可能地降低程式碼的閱讀負擔。
宣告
變數的宣告
儘管 JavaScript 語言並不要求在變數使用前先對變數進行宣告。但我們還是應該養成這個好習慣。這樣可以比較容易的檢測出那些未經宣告的變數,避免其變為隱藏的全域性變數,造成隱患。
在函式的開始應先用 var 關鍵字宣告函式中要使用的區域性變數,註釋變數的功能及代表的含義,且應以字母順序排序。每個變數單獨佔一行,以便新增註釋。這是因為 JavaScript 中只有函式的 {} 表明作用域,用 var 關鍵字宣告的區域性變數只在函式內有效,而未經 var 宣告的變數則被視為全域性變數。我們來看下清單 3。
清單 3. 區域性變數宣告
1 |
< script language="javascript"> var valueA = "a"; var valueB = "b"; function f1() { var valueA = "c"; alert("valueA="+valueA); //output: valueA=c valueB = "d"; alert("valueB="+valueB); //output: valueB=d } f1(); alert("valueA="+valueA); //output: valueA=a alert("valueB="+valueB); //output: valueB=d < /script> |
從上例的輸出驚奇地發現,用 var 宣告過的變數 valueA 和沒有宣告的變數 valueB 是有區別的。特別需要注意的是,在函式內部用 var 宣告的變數為區域性變數,這樣可以有效地避免因區域性變數和全域性變數同名而產生的錯誤。
函式的宣告
函式也應在呼叫前進行宣告,內部函式應在 var 宣告內部變數的語句之後宣告,可以清晰地表明內部變數和內部函式的作用域。
此外,函式名緊接左括號'(‘之間,而右括號’)’和後面的'{‘之間要有個空格,以清楚地顯示函式名以其引數部分,和函式體的開始。若函式為匿名 / 無名函式,則 function 關鍵字和左括號'(‘之間要留空格,否則可能誤認為該函式的函式名為 function。
清單 4. 內部函式宣告
1 |
< script language="javascript"> var innerA = 1; function outF() { var innerA = 2; function _inF() { alert("valueA="+innerA); } _inF(); } outF(); //output: valueA=2 _inF(); //error: innerF is not defined < /script> |
從清單 4 的輸出可以看出,inF() 函式僅在 outF() 函式的內部生效,區域性變數 innerA 對內部函式的作用域生效。這樣的編碼方式使得變數和函式的作用域變得清晰。
語句
對於簡單語句而言,需要提及的仍然是分號必要性,同時,一行最多有一個語句。如果一個賦值語句是用函式和物件來賦值,可能需要跨多行,一定切記要在賦值語句末加上分號。
這是因為 JavaScript 中,所有表示式都可以當語句,遇換行符時會解析為表示式的結束,此時不規範的換行和分號的丟失,可能引入新的錯誤。
對於複合語句,if, for, while, do, switch, try … catch 等程式碼體,函式定義的函式體,物件的定義等都需要放在花括號'{}’裡面。
- ‘{‘ 應在行末,標誌程式碼塊的開始。
- ‘}’ 應在一行開頭,標誌程式碼塊的結束,同時需要和'{‘所在行的開始對齊,以表明一個完整的複合語句段。這樣可以極大地提高程式碼的可閱讀性,控制邏輯能清晰地表現出來。
- 被包含的程式碼段應該再縮排 4 個空格。
- 即使被包含的程式碼段只有一句,也應該用花括號'{}’包含。儘管不用花括號程式碼也不會錯,但如若需要增加語句的話,則較容易因花括號遺漏而引起的編譯錯誤或邏輯錯誤。
return語句在使用時也需慎重,如果用表示式的執行作為返回值,請把表示式和 return 放在同一行中,以免換行符被誤解析為語句的結束而引起返回錯誤。return 關鍵字後若沒有返回表示式,則返回 undefined。構造器的預設返回值為 this。
清單 5. return 表示式
1 |
< script language="javascript"> function F1() { var valueA = 1; var valueB = 2; return valueA + valueB; } function F2() { var valueA = 1; var valueB = 2; return valueA + valueB; } alert( F1() ); //output: 3 alert( F2() ); //ouput: undefined < /script> |
在清單 5 中顯示了因返回表示式沒有和 return 關鍵字放在同一行而引起的返回錯誤,需重視。
特殊符號
空白符
適當的空白行可以大大提高程式碼的可閱讀性,可以使程式碼邏輯更清晰易懂。同時,在表示式中適當的留空白,也會給程式碼的閱讀帶來方便。
關鍵字的後面如有括號,則最好在關鍵字和左括號'(‘之間留空白,如 for, if, while 等。而函式名和括號之間則不宜留空白,但若是匿名函式,則必須在 function 和左括號'(‘之間留空白,否則,編輯器會誤認為函式名為 function。
在表示式中,二元運算子 ( 除左括號'(‘,左方括號'[‘,作用域點’.’) 和兩個運算元之間最好留空白。一元運算子(若不是詞 typeof 等)和其運算元之間不宜留空白。
逗號’,’的後面需要留空白,以顯示明確的引數間隔,變數間隔等。
分號’;’之後通常表明表達語句的結束,而應空行。在 for 的條件語句中,分號之後則應該留空白。
{ } 和 [ ]
在 JavaScript 中,如需定義空物件和空陣列,通常很自然地想到用 new Object() 和 new Array() 的方法。其實花括號'{}’和方括號'[]’可以直接用來定義一個空物件和一個空陣列。這種書寫方法可以使程式碼看起來簡單易懂。
== 和 ===
判斷”邏輯等”在程式碼裡太平常的不過事情了,但 JavaScript 與其他熟知的程式語言不同的是,除了可以使用兩個等號’==’來作判斷以為,還可以使用三個等號’===’來進行邏輯等判斷。兩者的不同是’==’作邏輯等判斷時,會先進行型別轉換後再進行比較。’===’則不會。因而,’==’進行的判斷結果可能產生偏差。’!=’與’!==’的區別亦是如此。本文提倡儘量使用’===’來進行邏輯等的判斷,用’!==’進行邏輯不等的判斷。
清單 6. === 的使用
1 |
< script language="javascript"> var valueA = "1"; var valueB = 1; if ( valueA == valueB) { alert("Equal"); } else { alert("Not equal") } //output: "Equal" if ( valueA === valueB) { alert("Equal"); } else { alert("Not equal") } //output: "Not equal" < /script> |
清單 6 中,valueA 和 valueB 兩個變數的值顯然是不相等的,起碼 valueA 是個字串,而 valueB 是一個數字。但用’==’進行判斷是,程式卻輸出相等的字樣。這是因為編譯器對兩個變數進行比較時,因為他們的型別不同,而自動地將 valueB 轉換成字串,而後再和 valueA 進行比較的。用’===’得到的判斷結果正和預期的結果相符。
+
加號’+’也同樣是程式設計師所熟知的操作符之一。JavaScript 和其他程式語言不同的是,在 JavaScript 中,’+’除了表示數字值相加,字串相連線以外,還可以作一元運算子用,把字串轉換為數字。因而如果使用不當,則可能與自增符’++’混淆而引起計算錯誤。這一點,在清單 7 中可以清楚地看出。
清單 7. 巧用 + 號
1 |
< script language="javascript"> var valueA = 20; var valueB = "10"; alert( valueA + valueB); //ouput: 2010 alert( valueA + (+valueB)); //output: 30 alert( valueA + +valueB); //output:30 alert( valueA ++valueB); //Compile error < /script> |
總結
本文就 JavaScript 程式碼的排版、命名、宣告、語句、和一些特殊字元的使用等方面,談了自己對 JavaScript 程式設計規範的建議。此外,還有許多方面需要深入瞭解研究,如 with, eval 語句和 this 物件的使用等等。我們在認識其普遍性的同時也需要注意其特殊性,在編寫程式碼時多用心留意,以創造更多更優質的程式程式碼。