總體規(guī)范
switch 下的 case 和 default 必須增加一個縮進層級
-
二元運算符兩側(cè)必須有一個空格,一元運算符與操作對象之間不允許有空格
var a = !arr.length; a++; a = b + c; 用作代碼塊起始的左花括號
{前必須有一個空格if / else / for / while / function / switch / do / try / catch / finally關(guān)鍵字后,必須有一個空格-
在對象創(chuàng)建時,屬性中的
:之后必須有空格,:之前不允許有空格var obj = { a: 1, b: 2, c: 3 }; // bad var obj = { a : 1, b:2, c :3 }; 函數(shù)聲明、具名函數(shù)表達式、函數(shù)調(diào)用中,函數(shù)名和
(之間不允許有空格,和;前不允許有空格-
在函數(shù)調(diào)用、函數(shù)聲明、括號表達式、屬性訪問、if / for / while / switch / catch 等語句中,() 和 [] 內(nèi)緊貼括號部分不允許有空格
// good callFunc(param1, param2, param3); save(this.list[this.indexes[i]]); needIncream && (variable += increament); if (num > list.length) { } while (len--) { } // bad callFunc( param1, param2, param3 ); save( this.list[ this.indexes[ i ] ] ); needIncreament && ( variable += increament ); if ( num > list.length ) { } while ( len-- ) { } 單行聲明的數(shù)組與對象,如果包含元素,
{}和[]內(nèi)緊貼括號部分不允許包含空格行尾不得有多余的空格
-
運算符處換行時,運算符必須在新行的行首
// good if (user.isAuthenticated() && user.isInRole('admin') && user.hasAuthority('add-admin') || user.hasAuthority('delete-admin') ) { // Code } var result = number1 + number2 + number3 + number4 + number5; // bad if (user.isAuthenticated() && user.isInRole('admin') && user.hasAuthority('add-admin') || user.hasAuthority('delete-admin')) { // Code } var result = number1 + number2 + number3 + number4 + number5; -
在函數(shù)聲明、函數(shù)表達式、函數(shù)調(diào)用、對象創(chuàng)建、數(shù)組創(chuàng)建、for語句等場景中,不允許在
,或;前換行// good var obj = { a: 1, b: 2, c: 3 }; foo( aVeryVeryLongArgument, anotherVeryLongArgument, callback ); // bad var obj = { a: 1 , b: 2 , c: 3 }; foo( aVeryVeryLongArgument , anotherVeryLongArgument , callback ); 不同行為或邏輯的語句集,使用空行隔開,更易閱讀
較復(fù)雜的邏輯條件組合,將每個條件獨立一行,邏輯運算符放置在行首進行分隔,或?qū)⒉糠诌壿嫲催壿嫿M合進行分隔。
-
建議最終將右括號
)與左大括號{放在獨立一行,保證與 if 內(nèi)語句塊能容易視覺辨識。if (user.isAuthenticated() && user.isInRole('admin') && user.hasAuthority('add-admin') || user.hasAuthority('delete-admin') ) { // Code } 按一定長度截斷字符串,并使用 + 運算符進行連接。
分隔字符串盡量按語義進行,如不要在一個完整的名詞中間斷開。
-
特別的,對于HTML片段的拼接,通過縮進,保持和HTML相同的結(jié)構(gòu)。
也可使用數(shù)組來進行拼接,相對 + 更容易調(diào)整縮進。var html = [ '<article>', '<h1>Title here</h1>', '<p>This is a paragraph</p>', '<footer>Complete</footer>', '</article>' ]; html = html.join(''); 當(dāng)參數(shù)過多時,將每個參數(shù)獨立寫在一行上,并將結(jié)束的右括號
)獨立一行。-
所有參數(shù)必須增加一個縮進。
foo( aVeryVeryLongArgument, anotherVeryLongArgument, callback );
也可以按邏輯對參數(shù)進行組合。
最經(jīng)典的是baidu.format函數(shù),調(diào)用時將參數(shù)分為“模板”和“數(shù)據(jù)”兩塊
baidu.format(
dateFormatTemplate,
year, month, date, hour, minute, second
);
當(dāng)函數(shù)調(diào)用時,如果有一個或以上參數(shù)跨越多行,應(yīng)當(dāng)每一個參數(shù)獨立一行。
這通常出現(xiàn)在匿名函數(shù)或者對象初始化等作為參數(shù)時,如setTimeout函數(shù)等。
setTimeout(
function () {
alert('hello');
},
200
);
order.data.read(
'id=' + me.model.id,
function (data) {
me.attchToModel(data.result);
callback();
},
300
);
-
鏈?zhǔn)秸{(diào)用較長時采用縮進進行調(diào)整。
$('#items') .find('.selected') .highlight() .end(); -
三元運算符由3部分組成,因此其換行應(yīng)當(dāng)根據(jù)每個部分的長度不同,形成不同的情況。
var result = thisIsAVeryVeryLongCondition ? resultA : resultB; var result = condition ? thisIsAVeryVeryLongResult : resultB; -
數(shù)組和對象初始化的混用,嚴(yán)格按照每個對象的 { 和結(jié)束 } 在獨立一行的風(fēng)格書寫。
var array = [ { // ... }, { // ... } ];
對于 if...else...、try...catch...finally等語句,推薦使用在}號后添加一個換行 的風(fēng)格,使代碼層次結(jié)構(gòu)更清晰,閱讀性更好。
不得省略語句結(jié)束的分號
在 if / else / for / do / while 語句中,即使只有一行,也不得省略塊{...}函數(shù)定義結(jié)束不允許添加分號
IIFE 必須在函數(shù)表達式外添加 (,非 IIFE 不得在函數(shù)表達式外添加 (
額外的 ( 能夠讓代碼在閱讀的一開始就能判斷函數(shù)是否立即被調(diào)用,進而明白接下來代碼的用途。而不是一直拖到底部才恍然大悟。
命名
變量 使用 Camel命名法
常量 使用 全部字母大寫,單詞間下劃線分隔 的命名方式
-
類 使用 Pascal命名法
function TextNode(options) { } -
類的 方法 / 屬性 使用 Camel命名法
function TextNode(value, engine) { this.value = value; this.engine = engine; } TextNode.prototype.clone = function () { return this; } 枚舉變量 使用 Pascal命名法,枚舉的屬性 使用 全部字母大寫,單詞間下劃線分隔 的命名方式
由多個單詞組成的縮寫詞,在命名中,根據(jù)當(dāng)前命名法和出現(xiàn)的位置,所有字母的大小寫與首字母的大小寫保持一致。
-
由多個單詞組成的縮寫詞,在命名中,根據(jù)當(dāng)前命名法和出現(xiàn)的位置,所有字母的大小寫與首字母的大小寫保持一致
function XMLParser() { } function insertHTML(element, html) { } var httpRequest = new HTTPRequest(); 類名 使用 名詞
函數(shù)名 使用 動賓短語
boolean 類型的變量使用 is 或 has 開頭
-
Promise對象 用 動賓短語的進行時 表達
var loadingData = ajax.get('url'); loadingData.then(callback);
注釋
單行注釋
必須獨占一行。// 后跟一個空格,縮進與下一行被注釋說明的代碼一致。多行注釋
避免使用 /.../ 這樣的多行注釋。有多行注釋內(nèi)容時,使用多個單行注釋-
文檔化注釋
為了便于代碼閱讀和自文檔化,以下內(nèi)容必須包含以 /*.../ 形式的塊注釋中文檔注釋前必須空一行
自文檔化的文檔說明 what,而不是 how 文件頂部必須包含文件注釋,用 @file 標(biāo)識文件說明
文件注釋中可以用 @author 標(biāo)識開發(fā)者信息命名空間使用 @namespace 標(biāo)識。
示例:
/**
* @namespace
*/
var util = {};
類和構(gòu)造函數(shù)
- 使用 @class 標(biāo)記類或構(gòu)造函數(shù)。
解釋:
對于使用對象 constructor 屬性來定義的構(gòu)造函數(shù),可以使用 @constructor 來標(biāo)記。
示例:
/**
* 描述
*
* @class
*/
function Developer() {
// constructor body
}
- 使用 @extends 標(biāo)記類的繼承信息。
示例:
/**
* 描述
*
* @class
* @extends Developer
*/
function Fronteer() {
Developer.call(this);
// constructor body
}
util.inherits(Fronteer, Developer);
- 使用包裝方式擴展類成員時, 必須通過 @lends 進行重新指向.沒有 @lends 標(biāo)記將無法為該類生成包含擴展類成員的文檔。
示例:
/**
* 類描述
*
* @class
* @extends Developer
*/
function Fronteer() {
Developer.call(this);
// constructor body
}
util.extend(
Fronteer.prototype,
/** @lends Fronteer.prototype */{
_getLevel: function () {
// TODO
}
}
);
- 類的屬性或方法等成員信息使用 @public / @protected / @private 中的任意一個,指明可訪問性。
解釋:
生成的文檔中將有可訪問性的標(biāo)記,避免用戶直接使用非 public 的屬性或方法。
示例:
/**
* 類描述
*
* @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 () {
};
函數(shù)/方法注釋
函數(shù)/方法注釋必須包含函數(shù)說明,有參數(shù)和返回值時必須使用注釋標(biāo)識
參數(shù)和返回值注釋必須包含類型信息和說明
// null 或 undefined
// good
if (noValue == null) {
// ......
}
// bad
if (noValue === null || typeof noValue === 'undefined') {
// ......
}
如果函數(shù)或全局中的 else 塊后沒有任何語句,可以刪除 else。
// good
function getName() {
if (name) {
return name;
}
return 'unnamed';
}
// bad
function getName() {
if (name) {
return name;
}
else {
return 'unnamed';
}
}
對循環(huán)內(nèi)多次使用的不變值,在循環(huán)外用變量緩存
// good
var width = wrap.offsetWidth + 'px';
for (var i = 0, len = elements.length; i < len; i++) {
var element = elements[i];
element.style.width = width;
// ......
}
// bad
for (var i = 0, len = elements.length; i < len; i++) {
var element = elements[i];
element.style.width = wrap.offsetWidth + 'px';
// ......
}
對有序集合進行順序無關(guān)的遍歷時,使用逆序遍歷。
解釋:
逆序遍歷可以節(jié)省變量,代碼比較優(yōu)化。
示例:
var len = elements.length;
while (len--) {
var element = elements[len];
// ......
}
類型轉(zhuǎn)換檢測
類型檢測優(yōu)先使用
typeof。對象類型檢測使用instanceof。null或undefined的檢測使用== null轉(zhuǎn)換成 string 時,使用 + ''。
示例:
// good
num + '';
// bad
new String(num);
num.toString();
String(num);
- 轉(zhuǎn)換成 number 時,通常使用 +。
示例:
// good
+str;
// bad
Number(str);
- string 轉(zhuǎn)換成 number,要轉(zhuǎn)換的字符串結(jié)尾包含非數(shù)字并期望忽略時,使用 parseInt。
示例:
var width = '200px';
parseInt(width, 10);
- 使用 parseInt 時,必須指定進制。
示例:
// good
parseInt(str, 10);
// bad
parseInt(str);
- 轉(zhuǎn)換成 boolean 時,使用 !!。
示例:
var num = 3.14;
!!num;
- number 去除小數(shù)點,使用 Math.floor / Math.round / Math.ceil,不使用 parseInt。
示例:
// good
var num = 3.14;
Math.ceil(num);
// bad
var num = 3.14;
parseInt(num, 10);
字符串
-
字符串開頭和結(jié)束使用單引號 '。
解釋:
輸入單引號不需要按住 shift,方便輸入。
實際使用中,字符串經(jīng)常用來拼接 HTML。為方便 HTML 中包含雙引號而不需要轉(zhuǎn)義寫法。
示例:var str = '我是一個字符串'; var html = '<div class="cls">拼接HTML可以省去雙引號轉(zhuǎn)義</div>'; -
使用 數(shù)組 或 + 拼接字符串。
解釋:
使用 + 拼接字符串,如果拼接的全部是 StringLiteral,壓縮工具可以對其進行自動合并的優(yōu)化。所以,靜態(tài)字符串建議使用 + 拼接。
在現(xiàn)代瀏覽器下,使用 + 拼接字符串,性能較數(shù)組的方式要高。
如需要兼顧老舊瀏覽器,應(yīng)盡量使用數(shù)組拼接字符串。
示例:// 使用數(shù)組拼接字符串 var str = [ // 推薦換行開始并縮進開始第一個字符串, 對齊代碼, 方便閱讀. '<ul>', '<li>第一項</li>', '<li>第二項</li>', '</ul>' ].join(''); // 使用 + 拼接字符串 var str2 = '' // 建議第一個為空字符串, 第二個換行開始并縮進開始, 對齊代碼, 方便閱讀 + '<ul>', + '<li>第一項</li>', + '<li>第二項</li>', + '</ul>';
對象
- 使用對象字面量 {} 創(chuàng)建新 Object。
示例:
// good
var obj = {};
// bad
var obj = new Object();
- 對象創(chuàng)建時,如果一個對象的所有 屬性 均可以不添加引號,則所有 屬性 不得添加引號。
示例:
var info = {
name: 'someone',
age: 28
};
- 對象創(chuàng)建時,如果任何一個 屬性 需要添加引號,則所有 屬性 必須添加 '。
解釋:
如果屬性不符合 Identifier 和 NumberLiteral 的形式,就需要以 StringLiteral 的形式提供。
示例:
// good
var info = {
'name': 'someone',
'age': 28,
'more-info': '...'
};
// bad
var info = {
name: 'someone',
age: 28,
'more-info': '...'
};
- 不允許修改和擴展任何原生對象和宿主對象的原型。
示例:
// 以下行為絕對禁止
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];
}
}
數(shù)組
使用數(shù)組字面量[]創(chuàng)建新數(shù)組,除非想要創(chuàng)建的是指定長度的數(shù)組。
示例:
// good
var arr = [];
// bad
var arr = new Array();
- 遍歷數(shù)組不使用 for in。
解釋:
數(shù)組對象可能存在數(shù)字以外的屬性, 這種情況下 for in 不會得到正確結(jié)果.
示例:
var arr = ['a', 'b', 'c'];
arr.other = 'other things'; // 這里僅作演示, 實際中應(yīng)使用Object類型
// 正確的遍歷方式
for (var i = 0, len = arr.length; i < len; i++) {
console.log(i);
}
// 錯誤的遍歷方式
for (i in arr) {
console.log(i);
}
不因為性能的原因自己實現(xiàn)數(shù)組排序功能,盡量使用數(shù)組的 sort 方法。
解釋:
自己實現(xiàn)的常規(guī)排序算法,在性能上并不優(yōu)于數(shù)組默認(rèn)的 sort 方法。以下兩種場景可以自己實現(xiàn)排序:需要穩(wěn)定的排序算法,達到嚴(yán)格一致的排序結(jié)果。
數(shù)據(jù)特點鮮明,適合使用桶排。清空數(shù)組使用 .length = 0。
函數(shù)
一個函數(shù)的長度控制在 50 行以內(nèi)。
解釋:
將過多的邏輯單元混在一個大函數(shù)中,易導(dǎo)致難以維護。一個清晰易懂的函數(shù)應(yīng)該完成單一的邏輯單元。復(fù)雜的操作應(yīng)進一步抽取,通過函數(shù)的調(diào)用來體現(xiàn)流程。特定算法等不可分割的邏輯允許例外。
一個函數(shù)的參數(shù)控制在 6 個以內(nèi)。
解釋:
除去不定長參數(shù)以外,函數(shù)具備不同邏輯意義的參數(shù)建議控制在 6 個以內(nèi),過多參數(shù)會導(dǎo)致維護難度增大。某些情況下,如使用 AMD Loader 的 require 加載多個模塊時,其 callback 可能會存在較多參數(shù),因此對函數(shù)參數(shù)的個數(shù)不做強制限制。
空函數(shù)不使用 new Function() 的形式。
示例:
var emptyFunction = function () {};
- 對于性能有高要求的場合,建議存在一個空函數(shù)的常量,供多處使用共享。
示例:
var EMPTY_FUNCTION = function () {};
function MyClass() {
}
MyClass.prototype.abstractMethod = EMPTY_FUNCTION;
MyClass.prototype.hooks.before = EMPTY_FUNCTION;
MyClass.prototype.hooks.after = EMPTY_FUNCTION;
元素樣式style
盡可能通過為元素添加預(yù)定義的 className 來改變元素樣式,避免直接操作 style 設(shè)置
通過 style 對象設(shè)置元素樣式時,對于帶單位非 0 值的屬性,不允許省略單位
之前寫的筆記,想要再找原文,找不到了。。只是知識的搬運工。