JavaScript 最佳實踐

這個文檔是基於JavaScript社區衆多開發者的意見和經驗,在開發JavaScript代碼上的最佳實踐和首選的方案的明細表。由於這是一個推薦的表而非原則性的方案,經驗豐富的開發者可能對下面的表達會有略有不一樣的看法。javascript

1. 老是使用 ‘var’

在JavaScript中,變量不是全局範圍的就是函數範圍的,使用」var」關鍵詞將是保持變量簡潔明瞭的關鍵。當聲明一個或者是全局或者是函數級(function-level)的變量,需老是前置」var」關鍵詞,下面的例子將強調不這樣作潛在的問題。php

不使用 var 形成的問題html

var i=0; // This is good - creates a global variable
function test() {
   for (i=0; i<10; i++) {
      alert("Hello World!");
   }
}
test();
alert(i); // The global variable i is now 10!

由於變量函數中變量 i 並無使用 var 使其成爲函數級的變量,在這個例子中它引用了全局變量。老是使用 var 來聲明全局變量是一個不少的作法,但相當重要的一點是使用 var 定義一個函數範圍的變量。下面這兩個方法在功能上是相同的:前端

正確的函數java

function test() {
   var i=0;
   for (i=0; i<10; i++) {
      alert("Hello World!");
   }
}

正確的函數程序員

function test() {
   for (var i=0; i<10; i++) {
      alert("Hello World!");
   }
}

2. 特性檢測而非瀏覽器檢測

一些代碼是寫來發現瀏覽器版本並基於用戶正使用的客戶端的對其執行不一樣行爲。這個,總的來講,是一個很是糟的實踐。更好的方法是使用特性檢測,在使用一個老瀏覽器可能不支持的高級的特性以前,首先檢測(瀏覽器的)是否有這個功能或特性,而後使用它。這單獨檢測瀏覽器版原本得更好,即便你知道它的性能。你能夠在 http://www.jibbering.com/faq/faq_notes/not_browser_detect.html找到一個深刻討論這個問題的文章。express

例子:數組

if (document.getElementById) {
   var element = document.getElementById('MyId');
}
else {
   alert('Your browser lacks the capabilities required to run this script!');
}

3. 使用方括號記法

當訪問由執行時決定或者包括要不能用」.」號訪問的對象屬性,使用方括號記法。若是你不是一個經驗豐富的JavaScript程序員,老是使用方括號是一個不錯的作法瀏覽器

對象的屬性由兩種固定的方法來訪問:」.」記法和」[ ]「方括號記法:服務器

「.」號記法

MyObject.property

「[ ]「方括號記法

MyObject["property"]

使用」.」號,屬性名是硬代碼,不能在執行時改變。使用」[ ]「方括號,屬性名是一個經過計算屬性名而來的字符串。字符串要以是硬代碼,也多是變量,甚至能夠是一個調回一個字母串值的函數。若是一個屬性名在執行產生,方括號是必須,若是你有 「value1″, 「value2″, 和 「value3″這樣的屬性,而且想利用變量 i=2來訪問

這個能夠運行:

MyObject["value"+i]

這個不能夠:

MyObject.value+i

而且在某些服務器端環境(PHP、Struts等)下,Form 表單被附加了 [ ] 號來表示 Form 表單在服務器端必須被看成數組來對待。如此,用」.」號來引用一個包含 [ ] 號的字段將不會執行,由於 [ ] 是引用一個 JavaScript 數組的語法。因此,[ ] 號記法是必須的:

這個能夠運行:

formref.elements["name[]"]

這個不能夠:

formref.elements.name[]

推薦使用」[ ]「方括號記法是說當其須要時(明顯地)老是使用它。當不是嚴格須要使用它的時候,它是一個私人的偏好和習慣。一個好的經驗原則是,使用」.」號記法訪問標準的對象屬性,使用」[ ]「方括號記法訪問由頁面定義的對象屬性。這樣,document["getElementById"]() 是一個完美可行的」[ ]「方括號記法用法,但 document.getElementById() 在語法上是首選,由於 getElementById 是一個 DOM 規範中定義的一個標準文檔對象屬性。混合使用這兩個記法使哪一個是標準對象屬性,哪一個屬性名是由上下文所定義的,在代碼中顯得清晰明瞭:

document.forms["myformname"].elements["myinput"].value

這裏,forms 是 document 的一個標準屬性,而表單名 myformname 則是由頁面所定義的。同時,elements 和 value 屬性都是由規範所定義的標準屬性。而 myinput 則是由頁面所定義的。這頁是句法讓人很是容易理解(代碼的內容),是一個推薦遵循的習慣用法,但不是嚴格原則。

4. 避免 ‘eval’

在JavaScript中,eval()功能是一個在執行期中執行任意代碼的方法。在幾乎全部的狀況下,eval 都不該該被使用。若是它出如今你的頁面中,則代表你所作的有更好的方法。舉一個例子,eval 一般被不知道要使用方括號記法的程序員所使用。

原則上,」Eval is evil(Eval是魔鬼)」。別使用它,除非你是一個經驗豐富的開發者而且知道你的狀況是個例外。

5. 正確地引用表單和表單元素

全部的 HTML 表單都應該有一個 name 屬性。對於 XHTML 文檔來講,name 屬性是不被要求的,但 Form 標籤中應有相應有 id 屬性,並必須用 document.getElementById() 來引用。使用像 document.forms[0] 這樣的索引方法來引用表單,在幾乎全部狀況下,是一個糟糕的作法。有些瀏覽器把文檔中使用 form 來命名的元素看成一個可用的 form 屬性。這樣並不可靠,不該該使用。

下面這個例子用使用方括號和正確的對象引用方法來展現如何防止錯誤地引用一個表單的input:

正確引用表單 Input:

document.forms["formname"].elements["inputname"]

糟糕的作法:

document.formname.inputname

若是你要引用一個函數裏的兩個表單元素,較好的作法是先引用這個form對象,並將其儲存在變量中。這樣避免了重複查詢以解決表單的引用:

var formElements = document.forms["mainForm"].elements;
formElements["input1"].value="a";
formElements["input2"].value="b";

當你使用 onChange 或者其餘相似的事件處理方法,一個好的作法是老是經過一個引來把 input 元素自己引用到函數中來。全部 input 元素都帶有一個對包含其在內的Form表單有一個引用:

<input type="text" name="address" onChange="validate(this)">
function validate(input_obj) {
   // 引用包含這個元素的form
   var theform = input_obj.form;
   // 如今你能夠不須要使用硬代碼來引用表單自身
   if (theform.elements["city"].value=="") {
      alert("Error");
   }
}

經過對錶單元素的引用來訪問表單的屬性,你能夠寫一個不包含硬代碼的函數來引用這個頁面中任何一個有特定名的表單。這是一個很是好的作法,由於函數變得可重用。

6. 避免 ‘with’

JavaScript 中的 with 聲明在一個做用域的前端插入一個對象,因此任何屬性/變量的引用將會倚着對象被首先解決。這一般被用做一個避免重複引用的快捷方法:

使用 with 的例子:

with (document.forms["mainForm"].elements) {
   input1.value = "junk";
   input2.value = "junk";
}

但問題在於程序員並無方法來驗證 input1 或 input2 實際上已經被看成 Form 元素數組的屬性來解決。它首先覺得這些名來檢測屬性,若是找不到,它將會繼續(向下)檢測這個做用域。最後,它在全局對象中嘗試把input1 和 input2 做爲一個全局對象來對待,而這以一個錯誤做爲結尾。

變通的方法是:建立一個引用來減小引用的對象,並使用它來解決這些引用。

使用一個引用:

var elements = document.forms["mainForm"].elements;
elements.input1.value = "junk";
elements.input2.value = "junk";

7. 在錨點中使用 「onclick」 替代 「javascript: Pseudo-Protocol」

若是你想在<a>標籤中觸發JavaScript 代碼,選擇 onclick 而非 javascript: pseudo-protocol;使用 onclick 來運行的 JavaScript 代碼必須返回 ture 或者false(or an expression than evalues to true or false [這句要怎麼翻譯呢? 我是這樣理解的:一個優先性高於true 或 false 的表達式])來返回標籤自己:若是返回 true,則錨點的 href 將被看成一個通常的連接;若是返回 false,則 href 會被忽略。這就是爲何」return false;」 常常被包含在 onclick 所處理代碼的尾部。

正確句法:

<a onclick="doSomething(); return false;" href="javascript_required.html>go</a>

在這個實例中,」doSomething()」 函數(定義於頁面的某個角落)將在被點擊時調用。href 將永遠不會被啓用了JavaScript 的瀏覽器訪問。在你能夠提醒JavaScript 是必須的、而用戶未啓用之的瀏覽器中,文檔 JavaScript_required.html 纔會被加載。一般,當你確保用戶將會開啓 JavaScript 支持,爲儘可能簡化,連接將只包含 href=」#」。 而這個作法是不被鼓勵的。一般有一個不錯的作法是:能夠提供沒用啓用 JavaScript 一個返回本地的頁面。

有時,衆多想要分狀況來訪問一個連接。例如,當一個用戶要離開你的一個表單頁面,而想先驗證來確保沒有東西被改變。在這個狀況下,你的 onclick 將會訪問一個返回詢問連接是否應該被遵循的函數:

有條件的連接訪問:

<a href="/" onClick="return validate();">Home</a>
function validate() {
	return confirm("Are you sure you want to exit this page?");
}

在這個實例中,validate() 函數必須只返回 ture 或 false。ture 的時候用戶將被容許問題 home 頁面,或 false 的時候連接不被訪問。這個例子提示確認(其行爲),以訪問 ture 或 false,這徹底由用戶點擊」確實」或者」取消」決定。

下面是一些」不該該」的例子。若是你在本身的頁面中看到下面這樣的代碼,這是不正確的,須要被修改:

什麼是不該該作的:

<a href="javascript:doSomething()">link</a>
<a href="#" onClick="doSomething()">link</a>
<a href="#" onClick="javascript:doSomething();">link</a>
<a href="#" onClick="javascript:doSomething(); return false;">link</a>

8. 使用一元 ‘+’ 號運算符使類型轉向Number

在JavaScript中,」+」號運算符同時充當數學加號和鏈接符。這會在form表單的域值相加時出現問題,例如,由於JavaScript是一個弱類型語言,form 域的值將會被看成數組來處理,而你把它們」+」一塊兒的時候,」+」將被當成鏈接符,而非數學加號。

有問題的例子:

<form name="myform" action="[url]">
<input type="text" name="val1" value="1">
<input type="text" name="val2" value="2">
</form>
function total() {
	var theform = document.forms["myform"];
	var total = theform.elements["val1"].value + theform.elements["val2"].value;
	alert(total); // 這個將會彈出 "12", 但你想要的是 3!
}

解決這個問題,JavaScript 須要一個提示來讓它把這些值當作數字來處理。你可使用」+」號來把數組轉換成數字。給變量或者表達式前置一個」+」號將會強制其看成一個數字來處理,而這也將使得數學」+」得以成功應用。

修改好的代碼:

function total() {
	var theform = document.forms["myform"];
	var total = (+theform.elements["val1"].value) + (+theform.elements["val2"].value);
	alert(total); // This will alert 3
}

 9. 避免 document.all

document.all 是由Microsoft 的 IE 所引進的,並非一個標準的 JavaScript DOM 特性。儘管大多數新的瀏覽器支持它以支持依賴於它的糟糕代碼,(而)還有不少瀏覽器是不支持的。

並無理由其餘方法都不適用,而一個老的IE瀏覽器(<5.0)須要支持,而在JavaScript中使用 document.all 做爲一個折衷方法。 你並不須要使用 document.all 來檢測其是否是IE瀏覽器,由於其餘瀏覽器如今通常都支持。

只把 document.all 當作最後的選擇:

if (document.getElementById) {
	var obj = document.getElementById("myId");
}
else if (document.all) {
	var obj = document.all("myId");
}

一些使用 document.all 的原則:

  •  同嘗試其餘方法
  •  當其做爲最後的選擇
  •  當須要支持 5.0 版本如下的 IE 瀏覽器
  •  老是使用 「if (document.all) { }」 來查看是否支持.

10. 不要在腳本代碼塊中使用HTML註釋

在 JavaScript 的舊日子(1995)裏,諸如 Netscape 1.0 的一些瀏覽器並不支持或認識 <script> 標籤。因此,當 JavaScript 第一次被髮布,須要有一個技術來讓實些代碼不被當作文本顯示於舊版瀏覽器上。有一個」hack」 是在代碼中使用 HTML 註釋來隱藏這些代碼。

使 HTML 註釋並很差:

<script language="javascript">
<!--
   // code here
//-->
</script>

在今天,沒有任何一個經常使用的瀏覽器會忽略掉 <script> 標籤。所以,再不必隱藏 JavaScript 源代碼。事實上,它還能夠由於下面的理由,被認爲是無益的:

  •  在 XHTML 文檔中,源代碼將向全部瀏覽器隱藏並被渲染成無用的(內容);
  •  – 在 HTML 註釋並不容許 ,這個會讓任何遞減操做將失效。

11. 避免亂用全局命名空間

通常不多須要所有變量和函數。全局使用將可能致使 JavaScript 源文件文檔衝突,和代碼停止。所以,一個好的作法是在一個全局命名空間內採用函數性的封裝。有多個方法能夠完成這個任務,有此相對比較複雜。最簡單的方法是建立一個全局對象,並把屬性和方法指派給這個對象:

建立一個命名空間:

var MyLib = {}; // global Object cointainer
MyLib.value = 1;
MyLib.increment = function() { MyLib.value++; }
MyLib.show = function() { alert(MyLib.value); }

MyLib.value=6;
MyLib.increment();
MyLib.show(); // alerts 7

命名空間也可使用 Closures(閉包?) 來建立,而且 Private Member Variables (私有變量?) 也能夠假裝於 JavaScript中。

12. 避免同步的 ‘Ajax’ 調用

當使用」Ajax」請求時,你要麼選擇異步模式,要麼使用同步模式。當瀏覽器行爲能夠繼續執行,異步模式將請求放在後臺執行,同步模式則會等待請求完成後才繼續。

應該避免同步模式作出的請求。這些請求將會對用戶禁用瀏覽器,直至請求返回。一旦服務器忙,並須要一段時間來完成請求,用戶的瀏覽器(或者 OS)將不能作任何其餘的事,直至請求超時。

若是你以爲本身的狀況須要同步模式,最大的多是你須要時間來從新想一下你的設計。不多(若是有的話)實際上須要同步模式的 Ajax 請求。

13. 使用 JSON

當須要將數據結構存儲成純文本,或者經過 Ajax 發送/取回數據結構,儘量使用 JSON 代替 XML。JSON (JavaScript Object Notation) 是一個更簡潔有效的數據存儲格式,而且不依賴任何語言(and is a language-neutral)。

14. 使用正確的 <script> 標籤

不在 <script> 中的使用LANGUAGE 屬性。一個合適的方式是建立以下的 JavaScript 代碼塊:

<script type="text/javascript">
// code here
</script>
相關文章
相關標籤/搜索