HTML&CSS&JavaScript 編碼規範

編碼規範
一、 HTML編碼規範

  1. 代碼風格

1.1 縮進與換行
[強制] 使用4個空格作爲一個縮進層級。
[建議] 每行不得超過120個字符。
1.2 命名
[強制] class 必須單詞全字母小寫,單詞間以 – 分隔。
[強制] class必須代表相應模塊或部件的內容或功能,不得以樣式信息進行命名。
[強制] 元素 id 必須保證頁面唯一。
[強制] 同一頁面,應避免使用相同的 name 和 id。
[建議] id 建議單詞全字幕小寫單詞間以 – 分隔。同項目必須保持風格一致。
[建議] id、class命名,在避免衝突並描述清楚的前提下儘可能短。
1.3 標籤
[強制] 標籤名必須使用小寫字母。
[強制] 對於無需自閉合的標籤,不允許自閉合。
常見無需自閉合的標籤有input、br、img、hr等
示例:

<input type="text" name="title">     //good
<input type="text" name="title" />     //bad

[強制] 對 HTML5 中規定允許省略的閉合標籤,不允許省略閉合標籤。
[強制] 標籤使用必須符合標籤嵌套規則。
比如div不得置於p中,tbody必須至於table中。
1.4 屬性
[強制] 屬性名必須使用小寫字母。
例如:

<table cellspacing="0">...</table>    //good
<table cellSpacing="0">...</table>    //bad

[強制] 屬性值必須用雙引號包圍。
例如:

<script src="babel.js"></script>    //good
<script src=’babel.js’></script>     //bad

[建議] 布爾類型的屬性,建議不添加屬性值。
[建議] 自定義屬性建議以 xxx- 爲前綴,推薦使用 data- 。
2. 通用

2.1 DOCTYPE
[強制] 使用 HTML5 的 doctype 來啓用標準模式,建議使用大寫的 DOCTYPE。
[建議] 啓用 IE Edge 模式。

<meta http-equiv="X-UA-Compatible" content="IE=Edge">

[建議] 在 html 標籤上設置正確lang屬性。
2.2 編碼
[強制] 頁面必須使用精簡模式,明確指定字符編碼。指定字符編碼的 meta 必須是 head 的第一個直接子元素。
[建議] HTML 文件使用 BOM 的 UTF-8 編碼。
2.3 CSS 和 JavaScript 的引入。
[強制] 引入 CSS 時必須指明 rel=”stylesheet”。
[建議] 引入 CSS 和 JavaScript 時無須指明 type 屬性。
[建議] 在 head 中引入頁面需要的所以 CSS 資源。
[建議] JavaScript 應當放在頁面末尾,或採用異步加載。
3. Head

3.1 title
[強制] 頁面必須包含 title 標籤聲明標題。
[強制] title 必須作爲 head 的直接子元素,
並緊隨 charset 聲明之後。
3.2 viewport
[建議] 若頁面欲對移動頁面友好,需指定頁面的 viewport。
4. 圖片
[強制] 禁止 img 的src 取值爲空。延遲加載的圖片也要增加默認的 src。
[強制] 爲圖片添加 alt 屬性。
[建議] 避免爲 img 添加不必要的 title 屬性。
[建議] 有下載需求的圖片採用 img 標籤實現,無下載需求的圖片採用 CSS 背景圖實現。
5. 表單

5.1 控件標題
[強制] 有文本標題的控件必須使用 label 標籤將其與其標籤相關聯。
兩種方式:
1. 將控件置於label內。
2. label 的 for 屬性指向控件的 id。
5.2 按鈕
[強制] 使用 button 元素時必須指明 type 屬性值。
[建議] 儘量不要使用按鈕類元素的 name 屬性。
6. 多媒體
[建議] 當在現代瀏覽器中使用 audio 以及 video 標籤來播放音頻、視頻時,應當注意格式。
音頻格式: MP3、WAV、Ogg
視頻格式: MP4、WebM、Ogg
[建議] 在支持 HTML5 的瀏覽器中優先使用 audio 和 video 標籤來定義音視頻元素。
[建議] 只在必要的時候開啓音視頻的自動播放。
7. 模板中的 HTML
[建議] 模板代碼的縮進優先保證 HTML 代碼的縮進規則。
[建議] 模板代碼應以保證 HTML 單個標籤語法的正確性爲基本原則。
[建議] 在循環處理模板數據構造表格時,若要求每行輸出固定的個數,建議先將數據分組,之後在循環輸出。

二、CSS編碼規範

1 命名

1.1 文件命名
常用的文件命名:
全局:global.css 結構:layout.css
模塊:module.css 主題:theme.css
較長的文件名必須以 – 中橫槓符連接,項目裏面的私有樣式文件:項目名-業務模塊名稱.css
1.2 選擇器命名
[強制] 在不是必須的情況下儘可能不用id選擇器。
1. 選擇器名字全小寫,不得使用大寫。
2. 較長選擇器名字之間使用-中橫杆連接。
3. 當判斷容易出現命名衝突的時候,命名需按規則:模塊名-你的選擇器名,如果出現多層級選擇器的情況(應儘量避免超過3級的情況),每個層級間使用-中橫杆連接,不建議直接使用嵌套。
[建議] 常用的選擇器命名

1 代碼風格
1.1 縮進
[強制] 統一使用 4 個空格縮進,不得使用 tab 和 2 個空格(沒規範前的縮進方式不管)。
1.2 空格
[強制] 選擇器跟 { 之間 必須包含空格。
例:

/* good */
.selector {
}

/* bad */
.selector{
}

[強制] 屬性跟 : 之間不能有空格, : 跟屬性之間必須包含空格。

.selector {
    color: white;
}

.selector {
    color:white; /* 或 color : white;*/
}

[強制] >、+、~ 選擇器的兩邊各保留一個空格。
1.3換行
[強制] 一個rule中有多個選擇器時,選擇器必須換行。
[強制] 屬性值之間必須換行。
[建議] 對於超長的樣式屬性值,可在 空格 或 , 處換行。
1.4行長度
[強制] 每行不得超過 120 個字符,除非單行不可分割(例如url超長)。
2 值與單位

2.1文本
[強制] 文本內容必須用雙引號包圍。
2.2數值
[強制] 數值爲 0 – 1 之間的小數,省略整數部分的0。
2.3單位
[強制] 數組爲 0 的屬性值需省略單位。
2.4 url()
[強制] url() 函數中的路徑不加引號。
[建議] url() 函數中的絕對路徑可省去協議名。
2.5顏色
[強制] RGB顏色值必須使用十六進制形式 #3f3f3f。不允許使用 rgb()。
帶有alpha(不透明度)的顏色信息可以使用 rgba()。不使用 rgba() 時每個逗號後須保留一個空格。
[強制] 顏色值可縮寫時,必須使用縮寫形式。
[強制] 顏色值不可使用顏色單詞。(如: red、green 等)
[建議] 顏色值中的英文字母使用小寫,如果採用大寫字母,則必須保證同一項目內是一致的。
3 通用

3.1選擇器
[強制] DOM節點的 id、class 屬性賦值時 = 之間不得有空格,屬性值必須用雙引號包圍,不得用單引號。
[強制] 如無必要,儘量不使用 id 選擇器,給 id、class 選擇器設置屬性時不需要添加類型選擇器進行限定。
[強制] id 選擇器不需嵌套其他選擇器。
3.2屬性縮寫
[建議] 在可以使用縮寫的情況下,儘量使用屬性縮寫。
[建議] 使用 border、margin、padding 等縮寫時,應注意確實需要設置多個方向的值時才使用縮寫,避免其他方向的有用值被覆蓋掉。
3.3屬性書寫順序
[建議] 按如下順序書寫:

1.  位置屬性(position, top, right, z-index , display, float, overflow 等)
2.  大小(widthheightpaddingmarginborder)
3.  文字系列(fontline-heightletter-spacingcolor-text-align等)
4.  視覺(backgroundcolorlist-style等)
5.  其他(animationtransition等)

3.4 變換與動畫
[強制] 使用 transition 時應指定 transition-property,不用 all。
3.5 屬性前綴
[建議] 屬性的私有前綴按長到短排列,按 : 對其
例:

/* good */
.tab {
    -webkit-transition: color .5s;
       -moz-transition: color .5s;
            transition: color .5s;
}

/* bad */
/* bad */
.tab {
    -webkit-transition: color .5s;
    -moz-transition: color .5s;
    transition: color .5s;
}

三、JavaScript編碼規範

1 代碼風格
1.1文件
[建議] JavaScript 文件使用無 BOM 的 UTF-8 編碼。
[建議] 在文件結尾處,保留一個空行。
1.2縮進
[強制] 使用 4 個空格做爲一個縮進層級,不允許使用 2 個空格或 tab 字符。
[強制] switch 下的 case 和 default 必須增加一個縮進層級。
1.3 空格
[強制] 二元運算符兩側必須有一個空格,一元運算符與操作對象之間不允許有空格。
[強制] 用作代碼塊起始的左花括號 { 前必須有一個空格。
[強制] if / else / for / while / function / switch / do / try / catch / finally 關鍵字後,必須有一個空格。
[強制] 在對象創建時,屬性中的 : 之後必須有空格,: 之前不允許有空格。
[強制] 函數聲明、具名函數表達式、函數調用中,函數名和 ( 之間不允許有空格。
[強制] , 和 ; 前不允許有空格。
[強制] 在函數調用、函數聲明、括號表達式、屬性訪問、if / for / while / switch / catch 等語句中,() 和 [] 內津貼括號部分不允許有空格。
[強制] 單行聲明的數組與對象,如果包含元素,{} 和 [] 內緊貼括號部分不允許包含空格。
[強制] 行尾不得有多餘的空格。
1.4 換行
[強制] 每個獨立語句結束後必須換行。
[強制] 每行不得超過 120 個字符。
[強制] 運算符處換行時,運算符必須在新行的行首。

/* good */
var result = number1 + number2 + number3
+ number4 + number5;
/* bad */
var result = number1 + number2 + number3 +
number4 + number5;

[強制] 在函數聲明、函數表達式、函數調用、對象創建、數組創建、for語句等場景中,不允許在 , 或 ; 前換行。
[建議] 不同行爲或邏輯的語句集,使用空行隔開,更易閱讀。
[建議] 在語句的行長度超過 120 時,根據邏輯條件合理縮進。
[建議] 對於 if…else…、try…catch…finally 等語句,推薦使用在 } 號後添加一個換行的風格,使代碼層次結構更清晰,閱讀性更好。
1.5 語句
[強制] 不得省略語句結束的分號。
[強制] 在 if / else / for / do / while 語句中,即使只有一行,也不得省略塊{…}。
[強制] 函數定義結束不允許添加分號。

// 如果是函數表達式,分號是不允許省略的。
var funcName = function() { 
};

[強制] IIFE 必須在函數表達式外添加 ( , 非 IIFE 不得在函數表達式外添加 ( 。
IIFE = Immediately-Invoked Function Expression
(能夠讓代碼在閱讀的一開始就能判斷函數是否立即被調用,進而明白接下來代碼的用途。而不是一直拖到底部才恍然大悟。)
例:

// good
var task = (function () {
   // Code
   return result;
})();

var func = function () {
};


// bad
var task = function () {
    // Code
    return result;
}();
var func = (function () {
});

1.6 命名
[強制] 變量 使用 Camel命名法。
[強制] 函數 使用 Camel命名法。
[強制] 函數的 參數 使用 Camel命名法。
[強制] 類的 參數 使用 Camel命名法。
[強制] 類 使用 Pascal命名法。
[強制] 類的 方法 / 屬性 使用 Camel命名法。
[強制] 枚舉變量 使用 Pascal命名法,枚舉的屬性 使用 全部字母大寫,單詞間下劃線分隔 的命名方式。
[強制] 命名空間 使用 Camel命名法。
[強制] 由多個單詞組成的縮寫,在命名中,根據當前命名法和出現的位置,所以字母的大小寫保持一致。
[強制] 類名 使用 名詞。
[建議] 函數名 使用 動賓短語。
[建議] Boolean 類型的變量使用 is 或 has 開頭。
[建議] Promise對象 用 動賓短語的進行時 表達。
1.7 註釋

1.7.1 單行註釋
[強制] 必須獨佔一行。 // 後跟一個空格,縮進與下一行被註釋說明的代碼一致。
1.7.2 多行註釋
[建議] 避免使用 // 這樣的多行註釋。有多行註釋內容時,使用多個單行註釋。
1.7.3 文檔化註釋
[強制] 爲了便於代碼閱讀和自文檔化,以下內容必須包含 /*…/ 形式的塊註釋中。
解釋:
1. 文件 2.namespace 3. 類 4. 函數或方法 5.類屬性
6. 事件 7. 全局變量 8. 常量 9. AMD 模塊
[強制] 文檔註釋前必須空一行。
[建議] 自文檔化身爲文檔說明what,而不是how。
1.7.4類型定義
[強制] 類型定義都是以 { 開始,以 } 結束。
常用的類型如:
{string}, {number}, {boolean}, {Object},{Function},{RegExp},{Array},{Date}。
[強制] 對於基本類型 {string}, {number}, {boolean},首字母必須小寫。

1.7.5 文件註釋
[強制] 文件頂部必須包含文件註釋,用 @file 標識文件說明。
示例:

/**
* @file Describe the file
*/

[建議] 文件註釋中可以用 @author 標識開發者信息。
@author 中的名字不允許被刪除。任何勞動成果都應該被尊重。
1.7.6命名空間註釋
[建議] 命名空間使用 @namespace 標識。
1.7.7類註釋
[建議] 使用 @class 標記類或構造函數。
示例:

/**
 * 描述
 *
 * @class
 */
function Developer() {
    // constructor body
}

示例:
[建議] 使用 @extends 標記類的繼承信息。

/**
 * 描述
 *
 * @class
 * @extends Developer
 */
function Fronteer() {
    Developer.call(this);
    // constructor body
}
util.inherits(Fronteer, Developer);

[強制] 使用包裝方式擴展類成員時, 必須通過 @lends 進行重新指向。
解釋:
沒有 @lends 標記將無法爲該類生成包含拓展類成員的文檔。
[強制] 類的屬性或方法等成員信息使用 @public / @protected / @private 中的任意一個,指明可訪問性。
示例:

/**
* 類描述
*
* @class
* @extends Developer
*/
function Fronteer() {
Developer.call(this);
// constructor body
}

util.extend(
Fronteer.prototype,
/** @lends Fronteer.prototype */{
_getLevel: function () {
// TODO
}
}
);

[強制] 類的屬性或方法等成員信息使用 @public / @protected / @private 中的一個,指明可訪問性。
示例:

/**
 * 類描述
 *
 * @class
 * @extends Developer
 */
var Fronteer = function () {
    Developer.call(this);

    /**
     * 屬性描述
     *
     * @type {string}
     * @private
     */
    this._level = 'T12';

    // constructor body
};
util.inherits(Fronteer, Developer);
/**
 * 方法描述
 *
 * @private
 * @return {string} 返回值描述
 */
Fronteer.prototype._getLevel = function () {
};

1.7.8函數/方法註釋
[強制] 函數/方法註釋必須包含函數聲明,有參數和返回值時必須使用註釋標記。
[強制] 參數和返回值註釋必須包含類型信息和說明。
[建議] 當函數是內部函數,外部不可訪問時,可以使用 @inner 標識。
[強制] 對 Object 中各項的描述, 必須使用 @param 標識。

/**
 * 函數描述
 *
 * @param {Object} option 參數描述
 * @param {string} option.url option項描述
 * @param {string=} option.method option項描述,可選參數
 */
function foo(option) {
    // TODO
}

1.7.9事件註釋
[強制] 必須使用 @event 標識事件,事件參數的標識與方法描述的參數標識相同。
[強制] 在會廣播事件的函數前使用 @fires 標識廣播的事件,在廣播事件代碼前使用 @event 標識事件。
[建議] 對於事件對象的註釋,使用 @param 標識,生成文檔時可讀性更好。。
1.7.10常量註釋
[強制] 常量必須使用 @const 標記,幷包含說明和類型信息。
示例:

/**
 * 常量說明
 *
 * @const
 * @type {string}
 */
var REQUEST_URL = 'myurl.do';

1.7.11複雜類型註釋
[建議] 對於類型未定義的複雜結構的註釋,可以使用 @typedef 標識來定義。
1.7.12 AMD 模塊註釋
[強制] AMD 模塊使用 @module 或 @exports 標識。
[強制] 對於已使用 @module 標識爲 AMD模塊 的引用,在 namepaths 中必須增加 module: 作前綴。
1.7.13細節註釋
[建議] 細節註釋遵循單行註釋的格式。說明必須換行時,每行是一個單行註釋的起始。
[強制] 有時我們會使用一些特殊標記進行說明。特殊標記必須使用單行註釋。常用標記:
解釋:
1. TODO:有功能待實現。此時需要對將要實現的功能進行簡單說明。
2. FIXME:該處代碼允許沒問題,但可能由於時間趕或者其他原因,需要修正。此時需要對如何修正進行簡單說明。
3. HACK:爲修正某些問題而寫的不太好或者使用了某些詭異手段的代碼。此時需要對思路或詭異手段進行描述。
4. XXX:該處存在缺陷。此時需要對陷阱進行描述。
2語言特性

2.1變量
[強制] 變量使用前必須通過 var 定義。
[強制] 每個 var 只能聲明一個變量。
[強制] 變量必須 即用即聲明,不得在函數或其他形式的代碼塊起始位置統一聲明所有變量。
解釋:
變量聲明與使用的距離越遠,出現的跨度越大,代碼的閱讀與維護成本越高。雖然JavaScript的變量時函數作用域,還是應該根據編程中的意圖,縮小變量出現的距離空間。
示例:

// good
function kv2List(source) {
    var list = [];

    for (var key in source) {
        if (source.hasOwnProperty(key)) {
            var item = {
                k: key,
                v: source[key]
            };
            list.push(item);
        }
    }

    return list;
}

// bad
function kv2List(source) {
    var list = [];
    var key;
    var item;

    for (key in source) {
        if (source.hasOwnProperty(key)) {
            item = {
                k: key,
                v: source[key]
            };
            list.push(item);
        }
    }

    return list;
}

2.2 條件
[強制] 在 Equality Expression 中使用類型嚴格的 === 。僅當判斷 null 或 undefined時,允許使用 == null 。
[建議] 儘可能使用簡介的表達式。
示例:

// 字符串爲空

// good
if (!name) {
    // ......
}

// bad
if (name === '') {
    // ......
}

// 字符串非空

// good
if (name) {
    // ......
}

// bad
if (name !== '') {
    // ......
}

// 數組非空

// good
if (collection.length) {
    // ......
}

// bad
if (collection.length > 0) {
    // ......
}

// good
if (!notTrue) {
    // ......
}

// bad
if (notTrue === false) {
    // ......
}

// null 或 undefined

// good
if (noValue == null) {
  // ......
}

// bad
if (noValue === null || typeof noValue === 'undefined') {
  // ......
}

[建議] 按執行頻率排列分支的順序。
解釋:
按執行頻率排列分支順序的好處是:
1. 容易找到最常見的情況,增加可讀性。
2. 提高執行效率。
[建議] 對於相同變量或表達式的多值條件,用 switch 代替 if 。
示例:

// good
switch (typeof variable) {
    case 'object':
        // ......
        break;
    case 'number':
    case 'boolean':
    case 'string':
        // ......
        break;
}

// bad
var type = typeof variable;
if (type === 'object') {
    // ......
} 
else if (type === 'number' || type === 'boolean' || type === 'string') {
    // ......
}

[建議] 如果函數或全局中的 else 塊後沒有任何語句,可以刪除 else。
2.3 循環
[建議] 不要在循環體中包含函數表達式,事先將函數提取到循環體外。
解釋:
循環體中的函數表達式,運行過程中會生成循環次數個函數對象。
示例:

// good
function clicker() {
    // ......
}

for (var i = 0, len = elements.length; i < len; i++) {
    var element = elements[i];
    addListener(element, 'click', clicker);
}


// bad
for (var i = 0, len = elements.length; i < len; i++) {
    var element = elements[i];
    addListener(element, 'click', function () {});
}

[建議] 對循環內多次使用的不變值,在循環外用變量緩存。
[建議] 對有序集合進行遍歷時,緩存 length。
[建議] 對有序集合進行順序無關的遍歷時,使用逆序遍歷。
解釋:逆序遍歷可以節省遍歷,代碼比較優化。
示例:

var len = elements.length;
while (len--) {
    var element = elements[len];
    // ......
}

2.4 類型

2.4.1 類型檢測
[建議] 類型檢測優先使用 typeof 。對象類型檢測使用 instanceof 。null 或undefined 的檢測使用 ==null 。
2.4.2 類型轉換
[建議] 轉換成 string 時,使用 + ‘’ 。
[建議] 轉換成 number 時,通常使用 + 。
[建議] string 轉換成 number,要轉換的字符串結尾包含非數字並期望忽略時,使用 parseInt 。
示例:
var width = ‘200px’;
parseInt(width, 10);
[強制] 使用 parseInt 時,必須指定進制。
示例:
// good
parseInt(str, 10);

// bad
parseInt(str);
[建議] 轉換成 Boolean 時,使用 !! 。
示例:
var num = 3.14;
!!num;
[建議] number 去除小數點,使用 Math.floor / Math.round / Math.ceil,不使用 parseInt。
2.5 字符串
[強制] 字符串開頭和結尾使用單引號 ‘ 。
解釋:
1. 輸入單引號不需要按住shift,方便輸入。
2. 實際使用中,字符串經常用來拼接HTML。爲方便HTML中包含雙引號而不需要轉義寫法。
[建議] 使用 + 拼接字符串。
[建議] 複雜的數據到視圖字符串的轉換過程,選用一種模板引擎。
2.6 對象
[強制] 使用對象字面量 {} 將創建新 object 。
[強制] 對象創建時,如果一個對象的所有 屬性 均可以不添加引號,則所有 屬性 不得添加引號。
[強制] 對象創建時,如果任何一個 屬性 需要添加引號,則所有 屬性 必須添加 ’ 。
[強制] 不允許修改和拓展任何原生對象和宿主對象的原型。
示例:
// 以下行爲絕對禁止
String.prototype.trim = function () {
};
[建議] 屬性訪問時,儘量使用 . 。
解釋:
屬性名符合 Identifier (標識符) 的要求,就可以通過 . 來訪問,否則就只能通過 [expr] 方式訪問。
通常在 JavaScript 中聲明的對象,屬性命名是使用 Camel 命名法,用 . 來訪問更清晰簡潔。部分特殊的屬性(比如來自後端的JSON),可能採用不尋常的命名方式,可以通過 [expr] 方式訪問。
示例:
info.age;
info[‘more-info’];
[建議] for in 遍歷對象時,使用 hasOwnProperty 過濾掉原型中的屬性。
示例:

var newInfo = {};
for (var key in info) {
    if (info.hasOwnProperty(key)) {
        newInfo[key] = info[key];
    }
}

2.7 數組
[強制] 使用數組字面量 [] 創建新數組,除非想要創建的時指定長度的數組。
[強制] 遍歷數組不使用 for in 。
[建議] 不因爲性能的原因自己實現數組排序功能,儘量使用數組的 sort 方法。
解釋:
自己實現的常規排序算法,在性能上並不優於數組默認的 sort 方法。以下兩種場景可以自己實現排序:
1. 需要穩定的排序算法,達到嚴格一致的排序結果。
2. 數據特點鮮明,適合使用桶排。
[建議] 情況數組使用 .length = 0 。
2.8 函數

2.8.1 函數的長度
[建議] 一個函數的長度控制在 50 行以內。
2.8.2 參數的設計
[建議] 一個函數的參數控制在 6 個以內。
解釋:
除去不定長參數以外,函數具備不同邏輯意義的參數建議控制在 6 個以內,過多參數會導致維護難度增大。
某些情況下,如使用 AMD Loader 的 require 加載多個模塊時,其 callback 可能會存在較多參數,因此對函數參數的個數不做強制限制。
[建議] 通過 options 參數傳遞非數據輸入型參數。
2.8.3 閉包
[建議] 在適當的時候將閉包內打對象置爲 null 。
2.8.4 空函數
[建議] 空函數不使用 new Function() 的形式。
示例:
var emptyFunction = function () {};
[建議] 對於性能有高要求的場合,建議存在一個空函數的常量,供多處使用共享。
2.9 面向對象
[強制] 類的繼承方案,實現時需要修正 constructor 。
解釋:
通常使用其他 library 的類繼承方案都會進行 constructor 修正。如果是自己實現的類繼承方案,需要進行 constructor 修正。
示例:

/**
 * 構建類之間的繼承關係
 * 
 * @param {Function} subClass 子類函數
 * @param {Function} superClass 父類函數
 */
function inherits(subClass, superClass) {
    var F = new Function();
    F.prototype = superClass.prototype;
    subClass.prototype = new F();
    subClass.prototype.constructor = subClass;
}

[建議] 聲明類時,保證 constructor 的正確性。
示例:

function Animal(name) {
    this.name = name;
}

// 直接prototype等於對象時,需要修正constructor
Animal.prototype = {
    constructor: Animal,

    jump: function () {
        alert('animal ' + this.name + ' jump');
    }
};

// 這種方式擴展prototype則無需理會constructor
Animal.prototype.jump = function () {
    alert('animal ' + this.name + ' jump');
};

[建議] 屬性在構造函數中聲明,方法在原型中聲明。
解釋:
原型對象的成員被所有實例共享,能節約內存佔用。所以編碼時我們應該遵守這樣的原則:原型對象包含程序不會修改的成員,如方法函數或配置項。

function TextNode(value, engine) {
    this.value = value;
    this.engine = engine;
}

TextNode.prototype.clone = function () {
    return this;
};

[強制] 自定義事件的 事件名 必須全小寫。
[強制] 自定義事件只能有一個 event 參數。如果事件需要傳遞較多信息,應仔細設計事件對象。
[建議] 設計自定義事件時,應考慮禁止默認行爲。
解釋:
常見禁止默認行爲的方式有兩種:
1. 事件監聽函數中 return false。
2. 事件對象中包含禁止默認行爲的方法,如preventDefault 。
2.10 動態特性

2.10.1 eval
[強制] 避免使用直接 eval 函數。
[強制] 儘量避免使用 eval 函數。
2.10.2 動態執行代碼
[建議] 使用 new Function 執行動態代碼。
解釋:
通過 new Function 生成的函數作用域時全局作用域,不會影響當前的本地作用域。如果有動態代碼執行的需求,建議使用 new Function。
示例:

var handler = new Function('x', 'y', 'return x + y;');
var result = handler($('#x').val(), $('#y').val());

2.10.3 with
[建議] 儘量不要使用 with 。
解釋:
使用 with 可能會增加代碼的複雜度,不利於閱讀和管理;也會對性能有影響。大多數使用 with 的場景都能使用其他方式較好的替代。所以,儘量不要使用 with。
2.10.4 delete
[建議] 減少delete的使用。
解釋:
如果沒有特別的需求,減少或避免使用delete。delete的使用會破壞部分 JavaScript 引擎的性能優化。
2.10.5 對象屬性
[建議] 避免修改外部傳入的參數。
[建議] 具備強類型的設計。
3 瀏覽器環境

3.1 模塊化

3.1.1 AMD
[強制] 使用 AMD 作爲模塊定義。
解釋:
AMD 作爲由社區認可的模塊定義形式,提供多種重載提供靈活的使用方式,並且絕大多數優秀的 Library 都支持 AMD,適合作爲規範。
目前,比較成熟的 AMD Loader有:
1. 官方實現的 require.js
2. 百度自己實現的 esl
[強制] 模塊 id 必須符合標準。
解釋:
模塊 id 必須符合以下約束條件:
1. 類型爲 string,並且是由 / 分割的一系列 terms 來組成。例如:this/is/a/module。
2. term 應該符合 [a-zA-Z0-9_-]+ 規則。
3. 不應該有 .js 後綴。
4. 跟文件的路徑保持一致。
3.1.2 define
[建議] 定義模塊時不要指明 id 和 dependencies 。
解釋:
在 AMD 的設計思想裏,模塊名稱是和所在路徑相關的,匿名的模塊更利於封包和遷移。模塊依賴應在模塊定義內部通過 local require 引用。
所以,推薦使用 define(factory) 的形式進行模塊定義。
[建議] 使用 return 來返回模塊定義。
3.1.3 require
[強制] 全局運行環境中,require 必須以 async require 形式調用。
解釋:
模塊的加載過程時異步的,require 必須以 async require 形式調用。
[強制] 模塊定義中只允許使用 local require,不允許使用 global require。
解釋:
在模塊定義中使用 global require,對封裝性是一種破壞。
在 AMD 裏,global require 是可以被重命名的。並且 Loader 甚至沒有全局的 require 變量,而是用 Loader 名稱做爲 global require。模塊定義不應該依賴使用的 Loader。
[強制] Package在實現時,內部模塊的 require 必須使用 relative id。
解釋:
對於任何可能通過 發佈-引入 的形式複用的第三方庫、框架、包,開發者所定義的名稱不代表使用者使用的名稱。因此不要基於任何名稱的假設。在實現源碼中,require 自身的其它模塊時使用 relative id。
[建議] 不會被調用的依賴模塊,在 factory 開始處統一 require。
解釋:
有些模塊是依賴的模塊,但不會在模塊實現中被直接調用,最爲典型的是 css / js / tpl 等 Plugin 所引入的外部內容。此類內容建議放在模塊定義最開始處統一引用。
3.2 DOM

3.2.1 元素獲取
[建議] 對於單個元素,儘可能使用 document.getElementById 獲取,避免使用document.all。
[建議] 對於多個元素的集合,儘可能使用 context.getElementsByTagName 獲取。其中 context 可以爲 document 或其他元素。指定 tagName 參數爲 * 可以獲得所有子元素。
[建議] 遍歷元素集合時,儘量緩存集合長度。如需多次操作同一集合,則應將集合轉爲數組。
3.2.2 樣式獲取
[建議] 獲取元素實際樣式信息時,應使用getComputedStyle 或 currentStyle。
3.2.3 樣式設置
[建議] 儘可能通過爲元素添加預定義的 className 來改變元素樣式,避免直接操作 style 設置。
[強制] 通過 style 對象設置元素樣式時,對於帶單位非 0 值的屬性,不允許省略單位。
3.2.4 DOM 操作
[建議] 操作 DOM 時,儘量減少頁面 reflow。
解釋:
頁面 reflow 時非常耗時的行爲,非常容易導致性能瓶頸。下面一些場景會觸發瀏覽器的 reflow:
1. DOM元素的添加、修改(內容)、刪除。
2. 應用新的樣式或者修改任何影響元素佈局的屬性。
3. Resize瀏覽器窗口、滾動頁面。
4. 讀取元素的某些屬性(offsetLeft、offsetTop、offsetHeight、offsetWidth、scrollTop/Left/Width/Height、clientTop/Left/Width/Height、getComputedStyle()、currentStyle(in IE)) 。
[建議] 儘量減少 DOM 操作。
解釋:
DOM 操作也是非常耗時的一種操作,減少 DOM 操作有助於提高性能。舉一個簡單的例子,構建一個列表。我們可以用兩種方式:
1. 在循環體中 createElement 並 append 到父元素中。
2. 在循環體中拼接 HTML 字符串,循環結束後寫父元素的 innerHTML。
第一種方法看起來比較標準,但是每次循環都會對 DOM 進行操作,性能極低。在這裏推薦使用第二種方法。
3.2.5 DOM事件
[建議] 優先使用 addEventListener / attachEvent 綁定事件,避免直接在HTML屬性中上午 expando 屬性綁定事件處理。
解釋:
expando 屬性綁定事件容易導致互相覆蓋。
[建議] 使用 addEventListener 時第三個參數使用 false 。
解釋:
標準瀏覽器中的 addEventListener 可以通過第三個參數指定兩種時間觸發模型:冒泡和捕獲。而 IE 的 attachEvent 僅支持冒泡的事件觸發。所以爲了保持一致性,通常 addEventListener 的第三個參數都爲 false。
[建議] 在沒有事件自動管理的框架支持下,應持有監聽器函數的引用,在適當時候(元素釋放、頁面卸載等)移除添加的監聽器。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章