縮排與分號
- 使用soft tab(4個空格)。
- 每條語句結尾都需要有分號。
/* 變數申明 */
var x = 1;
/* 表示式 */
x++;
/* do-while */
do {
x++;
} while (x < 10);
空格
不需要空格的情況:
- 物件的屬性名後
- 字首一元運算子後,字尾一元運算子前
- 函式呼叫括號前
- 無論是函式宣告還是函式表示式,'('前不要空格
- 陣列的'['後和']'前,物件的'{'後和'}'前,運算子'('後和')'前
// 一元運算子 和 三元運算子
++x;
y++;
z = x ? 1 : 2;
// 物件的屬性
var a = {
b: 1
};
// 陣列
var a = [1, 2];
// 運算子
var a = (1 + 2) * 3;
需要空格的情況:
- 二元運算子前後(加減乘除等)
- 三元運算子'?:'前後
- 程式碼塊'{'前
- 下列關鍵字前:else, while, catch, finally
- 下列關鍵字後:if, else, for, while, do, switch, case, try,catch, finally, with, return, typeof
- 單行註釋'//'後(若單行註釋和程式碼同行,則'//'前也需要)多行註釋'*'後物件的屬性值前
- for迴圈,分號後留有一個空格,前置條件如果有多個,逗號後留一個空格
- 無論是函式宣告還是函式表示式,'{'前一定要有空格
- 函式的引數之間
var doSomething = function(a, b, c) {
// do something
};
// '('前無空格
doSomething(item);
// 迴圈
for (i = 0; i < 6; i++) {
x++;
}
空行
- 變數宣告後(當變數宣告在程式碼塊的最後一行時,則無需空行)
- 註釋前(當註釋在程式碼塊的第一行時,則無需空行)
- 程式碼塊後(在函式呼叫、陣列、物件中則無需空行)
- 檔案最後保留一個空行
// 變數申明後,需要空行
var x = 1;
// 當變數申明位於最後一行時,無需空行
if (x >= 1) {
var y = x + 1;
}
var a = 2;
// 需要在此註釋之前空行
a++;
function b() {
// 當註釋位於程式碼塊首行時,無需空行
return a;
}
// 程式碼塊之後需要空行
for (var i = 0; i < 2; i++) {
if (true) {
return false;
}
continue;
}
var obj = {
foo: function() {
return 1;
},
bar: function() {
return 2;
}
};
換行
換行的地方,行末必須有','或者運算子。
需要換行的情況:
- 程式碼塊'{'後和'}'前
- 變數賦值後
- 判斷語句中的條件過多過長
不需要換行的情況:
- 下列關鍵字後:else, catch, finally
- 程式碼塊'{'前
var a = {
b: 1,
c: 2
};
if (condition) {
...
} else {
...
}
try {
...
} catch (e) {
...
} finally {
...
}
function test() {
...
}
var a,
foo = 7,
b, c, bar = 8;
// 判斷語句中的條件過多過長
if (boolean1 &&
boolean2 &&
boolean3) {
// do someting
}
註釋
單行註釋
- 雙斜線後,必須跟一個空格;
- 縮排與下一行程式碼保持一致;
- 不要寫在程式碼行之後。
if (condition) {
// 縮排與下一行程式碼保持一致
allowed();
}
多行註釋
- 最少三行, '*'後跟一個空格,具體參照右邊的寫法;
- 適合的場景:難於理解的程式碼段、可能存在錯誤的程式碼段、瀏覽器特殊的HACK程式碼、業務邏輯強相關的程式碼
/*
* one space after '*'
*/
var x = 1;
文件註釋
參考jsdoc,多用於註釋函式與類。
/**
* @func
* @desc 一個帶引數的函式
* @param {string} a - 引數a
* @param {number} b=1 - 引數b預設值為1
* @param {string} c=1 - 引數c有兩種支援的取值</br>1—表示x</br>2—表示xx
* @param {object} d - 引數d為一個物件
* @param {string} d.e - 引數d的e屬性
* @param {string} d.f - 引數d的f屬性
* @param {object[]} g - 引數g為一個物件陣列
* @param {string} g.h - 引數g陣列中一項的h屬性
* @param {string} g.i - 引數g陣列中一項的i屬性
* @param {string} [j] - 引數j是一個可選引數
*/
function foo(a, b, c, d, g, j) {
...
}
引號
最外層統一使用單引號。
let y = 'foo';
let z = '<div id="test"></div>';
變數命名
- 標準變數採用駝峰式命名(除了物件的屬性外)
- 'ID'在變數名中全大寫
- 'Android'在變數名中大寫第一個字母
- 'iOS'在變數名中小寫第一個,大寫後兩個字母
- 常量全大寫,用下劃線連線
- 建構函式,大寫第一個字母
var thisIsMyName;
var goodID;
var AndroidVersion;
var iOSVersion;
var MAX_COUNT = 10;
function Person(name) {
this.name = name;
}
函式
- 無論是函式宣告還是函式表示式,'('前不要空格,但'{'前一定要有空格;
- 函式呼叫括號前不需要空格;
- 立即執行函式外必須包一層括號;
- 不要給inline function命名;
- 引數之間用', '分隔,注意逗號後有一個空格;
- 一個函式內,最多3層縮排,專注於實現一件事。
var doSomething = function(item) {
// do something
};
function doSomething(item) {
// do something
}
doSomething(item);
// 立即執行函式
(function() {
return 1;
})();
// inline function
var a = [1, 2, function() {
...
}];
// 引數間以', '分割
var doSomething = function(a, b, c) {
// do something
};
括號
下列關鍵字後必須有大括號(即使程式碼塊的內容只有一行):if, else,for, while, do, switch, try, catch, finally, with。
// not good
if (condition)
doSomething();
// good
if (condition) {
doSomething();
}
null
適用場景:
- 初始化一個將來可能被賦值為物件的變數
- 與已經初始化的變數做比較
- 作為一個引數為物件的函式的呼叫傳參
- 作為一個返回物件的函式的返回值
不適用場景:
- 不要用null來判斷函式呼叫時有無傳參
- 不要與未初始化的變數做比較
// not good
function test(a, b) {
if (b === null) {
// not mean b is not supply
...
}
}
// good
var a = null;
if (a === null) {
...
}
undefined
永遠不要直接使用undefined進行變數判斷;
使用typeof和字串'undefined'對變數進行判斷。
// not good
if (person === undefined) {
...
}
// good
if (typeof person === 'undefined') {
...
}
jshint
- 用'===', '!=='代替'==', '!=';
- for-in裡一定要有hasOwnProperty的判斷;
- 不要在內建物件的原型上新增方法,如Array, Date;
- 不要在內層作用域的程式碼裡宣告瞭變數,之後卻訪問到了外層作用域的同名變數;
- 變數不要先使用後宣告;
- 不要在一句程式碼中單單使用建構函式,記得將其賦值給某個變數;
- 不要在同個作用域下宣告同名變數;
- 不要在一些不需要的地方加括號,例:delete(a.b);
- 不要使用未宣告的變數(全域性變數需要加到.jshintrc檔案的globals屬性裡面);
- 不要宣告瞭變數卻不使用;
- debugger不要出現在提交的程式碼裡;
- 陣列中不要存在空元素;
- 不要在迴圈內部宣告函式;
- 不要像這樣使用建構函式,例:new function () { ... }, new Object
// not good
if (a == 1) {
a++;
}
// good
if (a === 1) {
a++;
}
// good
for (key in obj) {
if (obj.hasOwnProperty(key)) {
// be sure that obj[key] belongs to the object and was not inherited
console.log(obj[key]);
}
}
// not good
Array.prototype.count = function(value) {
return 4;
};
// not good
var x = 1;
function test() {
if (true) {
var x = 0;
}
x += 1;
}
// not good
function test() {
console.log(x);
var x = 1;
}
// not good
new Person();
// good
var person = new Person();
// not good
delete(obj.attr);
// good
delete obj.attr;
// not good
if (a = 10) {
a++;
}
// not good
var a = [1, , , 2, 3];
// not good
var nums = [];
for (var i = 0; i < 10; i++) {
(function(i) {
nums[i] = function(j) {
return i + j;
};
}(i));
}
// not good
var singleton = new function() {
var privateVar;
this.publicMethod = function() {
privateVar = 1;
};
this.publicMethod2 = function() {
privateVar = 2;
};
};
雜項
- 不要混用tab和space,或在一處使用多個tab或space;
- 對上下文this的引用只能使用'_this', 'that', 'self'其中一個來命名;
- 行尾不要有空白字元;
- switch的falling through和no default的情況一定要有註釋特別說明;
- 不允許有空的程式碼塊。
function Person() {
// not good
var me = this;
// good
var _this = this;
// good
var that = this;
// good
var self = this;
}
目錄索引
前端工程程式碼規範(一)——命名規則與工程約定
前端工程程式碼規範(二)——HTML
前端工程程式碼規範(三)——CSS, SCSS