[TOC]
JavaScript 是網頁的第三個主要部件。在網頁上適當地應用JavaScript 代碼,通過綁定事件和控制整體行為層,能夠增強整體的用戶和基于瀏覽器的體驗。
隨著功能強勁的新瀏覽器撐起基于瀏覽器的完整web應用,JavaScript 在近年的流行度爆棚。另外,對Javascript的細致運用為全面操控另外兩個部件 --?[HTML 標記](http://coderlmn.github.io/code-standards/#markup)和?[CSS](http://coderlmn.github.io/code-standards/#css)?-- 提供了手段。現在,在無需刷新整個頁面的情況下,頁面結構和頁面視覺樣式都可以被實時操控。
## JavaScript庫
我們開發新應用主要會用到?[jQuery](http://api.jquery.com/),不過我們對原生 JavaScript 和所有現代 javascript 庫也具有專業經驗。
## 編碼總體原則
* 99%的代碼必須封裝在外部Javascript文件中。這些文件必須在 BODY 標簽的尾部引入,讓頁面的性能最大化。
* 不要依賴于 user-agent 字符串。進行適當的特性檢測. (更多信息參見?[深入 HTML5: 檢測](http://diveintohtml5.info/detect.html)?和[jQuery 支持文檔](http://api.jquery.com/jQuery.support/))
* 不要使用 document.write()。
* 所有布爾變量的命名必須用 "is" 開頭
對正條件的測試
~~~
isValid = (test.value >= 4 && test.success);
~~~
* 給變量和函數的命名要有邏輯意義:例如:?`popUpWindowForAd`?就比?`myWindow`?好多了。
* 不要人為縮短命名到最小。除了傳統的?`for`?循環中的計數器?`i`?等簡化的情況,變量命名必須長到有明確意義。
* 文檔必須遵循?[NaturalDocs](http://www.naturaldocs.org/documenting.html)?結構。
* 常量或配置變量(例如動畫持續時間等)必須放在文件的頂部。
* 盡力編寫可通用化的函數,讓它接受參數并返回值。這樣有利于充分的代碼重用,而且一旦與引入及外部腳本配合起來,能在腳本需要修改時減少開銷。例如,相比硬編碼一個帶有窗口大小、選項和url的彈出式窗口,不如編寫一個接受大小、url和選項作為變量的函數。
* 給代碼添加注釋!這會有利于減少在調試Javascript函數上花費的時間。
* 不要把時間浪費在用?`<!-- -->`?給你的內聯Javascript加注釋上,除非你還在關注 Netscape 4。?:)
* 把你的代碼組織成一套?[對象常量/單例](http://kaijaeger.com/articles/the-singleton-design-pattern-in-javascript.html),按照?[模塊化模式](http://www.yuiblog.com/blog/2007/06/12/module-pattern/),或做成?[帶構造器的對象](http://mckoss.com/jscript/object.htm)。
* 最小化全局變量 - 你創建的全局變量越少越好。一般來說,用于你的應用命名空間,1會是個好的數字。
在描述任何全局變量的時候要明確指認。
~~~
window.globalVar = { ... }
~~~
### 留空
總的來說,使用留空應該遵循源遠流長的英語閱讀慣例。 例如,每個逗號和冒號(以及適用的分號)后面要空一格,但在括號內部的左側和右側都不要加空格。另外,大括號應該總是和他們前面的參數出現在同一行。
來看看下面的 JavaScript for循環的例子...
正確
~~~
for (var i = 0, j = arr.length; i < j; i++) {
// Do something.
}
~~~
不正確
~~~
for ( var i = 0, j = arr.length; i < j; i++ )
{
// Do something.
}
~~~
也不正確
~~~
for(var i=0,j=arr.length;i<j;i++){
// Do something.
}
~~~
### plugins.js 和 script.js
從 H5BP 開始我們看到了兩個文件, plugins.js 和 script.js。本節概述這兩個文件的基本用法。
#### plugins.js
Plugins.js 的用處是存放網站的所有插件代碼。相比鏈接到很多不同的文件,我們可以把插件代碼統一放到這個文件里,從而改善性能。這種用法會有也應該有例外。例如,一個超級大的插件,又只是用在一個很少被訪問到的頁面上,放在單獨的一個下載鏈接里就會更好,這樣只會在目標頁面被打開的時候才會被訪問。不過,大部分情況下,直接把所有插件的最小化版本粘貼到這里以便訪問是靠譜的。
下面就是一個樣例文件,包括一個小目錄。它可以作為所用到插件的隨身指南,包括文檔URL,使用它們的思路,諸如此類。
~~~
/* PLUGIN DIRECTORY
本文件中出現的插件 [按出場順序排序]
1.) Animate Background Position - http://plugins.jquery.com/project/backgroundPosition-Effect
2.) jQuery Easing Plugin - http://gsgd.co.uk/sandbox/jquery/easing/
3.) jQuery Ajax Form plugin - http://jquery.malsup.com/form/#download
4.) jQuery validation plugin (form validation) - http://docs.jquery.com/Plugins/Validation
-password strength
5.) Styled Selects (lightweight) - http://code.google.com/p/lnet/wiki/jQueryStyledSelectOverview
*/
/**
* 1.) Animate Background Position - http://plugins.jquery.com/project/backgroundPosition-Effect
* @author Alexander Farkas
* v. 1.21
*/
(function($) {
if(!document.defaultView || !document.defaultView.getComputedStyle){ // IE6-IE8
//SNIPPED
};
})(jQuery);
/**
* 2.) jQuery Easing Plugin (we're not using jQuery UI as of yet) - http://gsgd.co.uk/sandbox/jquery/easing/
*/
// t: current time, b: begInnIng value, c: change In value, d: duration
jQuery.easing['jswing'] = jQuery.easing['swing'];
jQuery.extend( jQuery.easing,
{
//SNIPPED
});
;(function($) {
$.fn.ajaxSubmit = function(options) {
//SNIPPED
}
})(jQuery);
/*
* jQuery Styled Select Boxes
* version: 1.1 (2009/03/24)
* @requires jQuery v1.2.6 or later
*
* Examples and documentation at: http://code.google.com/p/lnet/wiki/jQueryStyledSelectOverview
*
* Copyright (c) 2008 Lasar Liepins, liepins.org, liepins@gmail.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
jQuery.fn.styledSelect = function(settings) {
//SNIPPED
return this;
};
~~~
#### Script.js
Script.js 的用處是存放網站或應用的代碼代碼。再次說明,這種方式并不總是最佳解決方案,因為更大的團隊 和/或 規模更大、功能更多的項目可以得益于將應用代碼分解為模塊或功能特性相關的文件。不過,對于較小較簡單的應用,以及最初的原型開發,把所有工作集中到 scripts.js 還是靠譜的。
下面是一個簡化了的例子,用到了?[基于標記的低調全面的DOM-ready執行](http://paulirish.com/2009/markup-based-unobtrusive-comprehensive-dom-ready-execution/)?模式(【譯者注】這里的‘低調’原文是Unobtrusive ,是一種將Javascript從HTML結構抽離的設計概念,避免在HTML標簽中夾雜一堆onchange、onclick……等屬性去掛載Javascript事件,讓HTML與Javascript分離,依MVC的原則將功能權責清楚區分,使HTML也變得結構化容易閱讀。),看起來會類似于這樣:
~~~
/* Name: Demo
Author: Demo King */
/*demo namespace*/
demo = {
common : {
init : function(){
//initialize
},
finalize : function(){
//finalize
},
config : {
prop : "my value",
constant : "42"
}
},
mapping : {
init : function(){
//create a map
},
geolocate : function(){
//geolocation is cool
},
geocode : function(){
//look up an address or landmark
},
drawPolylines : function(){
//draw some lines on a map
},
placeMarker : function(){
//place markers on the map
}
}
}
~~~
## 變量,ID 及 class
所有的 JavaScript 變量必須寫成全小寫或駝峰法。一個例外是構造器函數,按慣例是首字母大寫。所有CSS里的?`id`?和?`class`?聲明都必須只用小寫。不允許用連接符或下劃線。
### 事件代理
在分配低調(unobtrusive)的事件監聽器時,通常可接受的做法是把事件監聽器直接分派給那些會觸發某個結果動作的元素。不過,偶爾也會有多個元素同時符合觸發條件,給每個元素都分配事件監聽器可能會對性能有負面影響。這種情況下,你就應該改用事件代理了。
從性能角度考慮,jQuery的?[delegate()](http://api.jquery.com/delegate)?優于?[live()](http://api.jquery.com/live)。
### 調試
即使采用了最好的校驗器,瀏覽器的怪異性也會不可避免地產生一些問題。有幾個堪稱無價之寶的工具可以幫助優化代碼的健全性和加載速度。很重要的一點是,你手頭準備好了這些工具,不管你主要用來開發的瀏覽器是哪個。我們推薦先在Firefox和Safari上做開發,然后用Google Chrome和Opera,最后針對IE用條件判斷做一些額外的微調。下面列出的是一些有幫助的調試器和速度分析器:
* **Firefox**:?[Firebug](http://getfirebug.com/),?[Page Speed](http://code.google.com/speed/page-speed/),?[YSlow](http://developer.yahoo.com/yslow/)
* **Safari**:?[Web Inspector](http://developer.apple.com/safari/library/documentation/AppleApplications/Conceptual/Safari_Developer_Guide/UsingtheWebInspector/UsingtheWebInspector.html)
* **Google Chrome**:?[Developer Tools](http://google.com/chrome/intl/en/webmasters-faq.html#tools)
* **Opera**:?[Dragonfly](http://opera.com/dragonfly/)
* **Internet Explorer 6-7**:?[Developer Toolbar](http://microsoft.com/downloads/details.aspx?familyid=E59C3964-672D-4511-BB3E-2D5E1DB91038)
* **Internet Explorer 8-10**:?[Developer Tools](http://msdn.microsoft.com/en-us/library/dd565625(v=VS.85).aspx)
### 優化 JavaScript 的特征
* 編寫可維護的代碼
* 單變量模式
* Hoisting:把所有變量聲明統一放到函數的起始位置 (在后部聲明的變量也會被JS視為在頭部定義,由此會產生問題)
* 不要擴充內置原型(雖然給Object(), Function()之類的內置原型增加屬性和方法很巧妙,但是會破壞可維護性)
* 不要用隱含的類型轉換
* 不要用 eval()
* 用 parseInt() 進行數字轉換
* (規范)左大括號的位置
* 構造器首字母大寫
* 寫注釋
* 不要用 void
* 不要用 with 語句
* 不要用 continue 語句
* 盡量不要用位運算
Stoyan Stefanov 的博文包含了以上原則?[并有詳細說明](http://net.tutsplus.com/tutorials/javascript-ajax/the-essentials-of-writing-high-quality-javascript/)(【譯者注】這篇博文值得一看)。