編碼規範
一、 HTML編碼規範
- 代碼風格
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 模式。
[建議] 在 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. 大小(width,height,padding,margin,border)
3. 文字系列(font,line-height,letter-spacing,color-text-align等)
4. 視覺(background,color,list-style等)
5. 其他(animation,transition等)
3.4 變換與動畫
[強制] 使用 transition 時應指定 transition-property,不用 all。
3.5 屬性字首
[建議] 屬性的私有字首按長到短排列,按 : 對其
例:
/* good */
.tab {
-webkit-transition: color .s;
-moz-transition: color .s;
transition: color .s;
}
/* bad */
/* bad */
.tab {
-webkit-transition: color .s;
-moz-transition: color .s;
transition: color .s;
}
三、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 > ) {
// ......
}
// 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 = , len = elements.length; i < len; i++) {
var element = elements[i];
addListener(element, 'click', clicker);
}
// bad
for (var i = , 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。
[建議] 在沒有事件自動管理的架構支援下,應持有監聽器函數的引用,在适當時候(元素釋放、頁面解除安裝等)移除添加的監聽器。