Javascript編碼規範

是曾小白吖發表於2020-02-14

1 前言

本文件的目標是使研發中心的各位同學js能夠按照統一規範進行編寫,使其風格保持一致,便於理解和維護。

2 程式碼風格

2.1 檔案

[建議] 在檔案結尾處,保留一個空行。

2.2 結構

2.2.1 縮排

  1. [強制] 使用 2 個空格做為一個縮排層級,不允許使用 4 個空格 或 tab 字元。
  2. [強制] switch 下的 case 和 default 必須增加一個縮排層級。

示例

// good
switch (variable) {

  case '1':
    // do...
    break;

  case '2':
    // do...
    break;

  default:
    // do...

}

// bad
switch (variable) {

case '1':
  // do...
  break;

case '2':
  // do...
  break;

default:
  // do...

}
複製程式碼

2.2.2 空格

  1. [強制] 二元運算子兩側必須有一個空格,一元運算子與操作物件之間不允許有空格。

示例

var a = !arr.length;
a++;
a = b + c;
複製程式碼
  1. [強制] 用作程式碼塊起始的左花括號 { 前必須有一個空格。

示例

// good
if (condition) {
}

while (condition) {
}

function funcName() {
}

// bad
if (condition){
}

while (condition){
}

function funcName(){
}
複製程式碼
  1. [強制] if / else / for / while / function / switch / do / try / catch / finally 關鍵字後,必須有一個空格。

示例

// good
if (condition) {
}

while (condition) {
}

(function () {
})();

// bad
if(condition) {
}

while(condition) {
}

(function() {
})();
複製程式碼
  1. [強制] 在物件建立時,屬性中的 : 之後必須有空格,: 之前不允許有空格。

示例

// good
var obj = {
  a: 1,
  b: 2,
  c: 3
};

// bad
var obj = {
  a : 1,
  b:2,
  c :3
};
複製程式碼
  1. [強制] 函式宣告、具名函式表示式、函式呼叫中,函式名和 ( 之間不允許有空格。

示例

// good
function funcName() {
}

var funcName = function funcName() {
};

funcName();

// bad
function funcName () {
}

var funcName = function funcName () {
};

funcName ();
複製程式碼
  1. [強制] , 和 ; 前不允許有空格。如果不位於行尾,, 和 ; 後必須跟一個空格。

示例

// good
callFunc(a, b);

// bad
callFunc(a , b) ;
複製程式碼
  1. [強制] 在函式呼叫、函式宣告、括號表示式、屬性訪問、if / for / while / switch / catch 等語句中,() 和 [] 內緊貼括號部分不允許有空格。

示例

// 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-- ) {
}
複製程式碼
  1. [強制] 單行宣告的陣列與物件,如果包含元素,{} 和 [] 內緊貼括號部分不允許包含空格

示例

// good
var arr1 = [];
var arr2 = [1, 2, 3];
var obj1 = {};
var obj2 = {name: 'obj'};
var obj3 = {
  name: 'obj',
  age: 20,
  sex: 1
};

// bad
var arr1 = [ ];
var arr2 = [ 1, 2, 3 ];
var obj1 = { };
var obj2 = { name: 'obj' };
var obj3 = {name: 'obj', age: 20, sex: 1};
複製程式碼
  1. [強制] 行尾不得有多餘的空格。

2.2.3 換行

  1. [強制] 每個獨立語句結束後必須換行。
  2. [強制] 每行不得超過 120 個字元。(注: 超長的不可分割的程式碼允許例外,比如複雜的正規表示式。長字串不在例外之列。)
  3. [強制] 運算子處換行時,運算子必須在新行的行首。

示例

// 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;
複製程式碼
  1. [強制] 在函式宣告、函式表示式、函式呼叫、物件建立、陣列建立、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
);
複製程式碼
  1. [建議] 不同行為或邏輯的語句集,使用空行隔開,更易閱讀。

示例

// 僅為按邏輯換行的示例,不代表setStyle的最優實現
function setStyle(element, property, value) {
  if (element == null) {
    return;
  }

  element.style[property] = value;
}
複製程式碼
  1. [建議] 在語句的行長度超過 120 時,根據邏輯條件合理縮排。
  2. [建議] 對於 if...else...、try...catch...finally 等語句,推薦使用在 } 號後新增一個換行 的風格,使程式碼層次結構更清晰,閱讀性更好。

示例

if (condition) {
  // some statements;
}
else {
  // some statements;
}

try {
  // some statements;
}
catch (ex) {
  // some statements;
}
複製程式碼

2.2.4 語句

  1. [強制] 不得省略語句結束的分號。
  2. [強制] 在 if / else / for / do / while 語句中,即使只有一行,也不得省略塊 {...}。

示例

// good
if (condition) {
  callFunc();
}

// bad
if (condition) callFunc();
if (condition)
    callFunc();
複製程式碼
  1. [強制] 函式定義結束不允許新增分號。

示例

// good
function funcName() {
}

// bad
function funcName() {
};

// 如果是函式表示式,分號是不允許省略的。
var funcName = function () {
};
複製程式碼

2.3 命名

  1. [強制] 變數 使用駝峰命名法。

示例

var loadingModules = {};
複製程式碼
  1. [強制] 常量 使用 全部字母大寫,單詞間下劃線分隔 的命名方式。

示例

var HTML_ENTITY = 333;
複製程式碼
  1. [強制] 函式 使用駝峰命名法。

示例

function stringFormat(source) {
}
複製程式碼
  1. [強制] 函式的引數 使用駝峰命名法。

示例

function hear(theBells) {
}
複製程式碼
  1. [強制] 列舉變數 使用 Pascal命名法,列舉的屬性 使用 全部字母大寫,單詞間下劃線分隔 的命名方式。

示例

var TargetState = {
  READING: 1,
  READED: 2,
  APPLIED: 3,
  READY: 4
};
複製程式碼
  1. [建議] 函式名 使用 動賓短語。

示例

function getStyle(element) {
}
複製程式碼

7.[建議] boolean 型別的變數使用 is 或 has 開頭。

示例

var isReady = false;
var hasMoreCommands = false;
複製程式碼

2.4 註釋

2.4.1 單行註釋

[強制] 必須獨佔一行。// 後跟一個空格,縮排與下一行被註釋說明的程式碼一致。

2.4.2 多行註釋

[建議] 避免使用 / * ... */ 這樣的多行註釋。有多行註釋內容時,使用多個單行註釋。

2.4.3 文件化註釋

[強制] 為了便於程式碼閱讀和自文件化,以下內容必須包含以 /**...*/ 形式的塊註釋中。 [強制] 文件註釋前必須空一行。

  1. 檔案
  2. namespace
  3. 函式或方法
  4. 類屬性
  5. 事件
  6. 全域性變數
  7. 常量
  8. AMD 模組

2.4.4 檔案註釋

[強制] 檔案頂部必須包含檔案註釋,用 @file 標識檔案說明。 [建議] 檔案註釋中可以用 @author 標識開發者資訊。

示例

/**
 * @file Describe the file
 * @author author-name(mail-name@domain.com)
 *         author-name2(mail-name2@domain.com)
 */
複製程式碼

2.4.5 函式/方法註釋

[強制] 函式/方法註釋必須包含函式說明,有引數和返回值時必須使用註釋標識。 [強制] 引數和返回值註釋必須包含型別資訊,且不允許省略引數的說明。

示例

/**
 * 函式描述
 *
 * @param {string} p1 引數1的說明
 * @param {string} p2 引數2的說明,比較長
 *     那就換行了.
 * @param {number=} p3 引數3的說明(可選)
 * @return {Object} 返回值描述
 */
function foo(p1, p2, p3) {
    var p3 = p3 || 10;
    return {
        p1: p1,
        p2: p2,
        p3: p3
    };
}
複製程式碼

2.4.6 細節註釋

[強制] 有時我們會使用一些特殊標記進行說明。特殊標記必須使用單行註釋的形式。下面列舉了一些常用標記:

  1. TODO: 有功能待實現。此時需要對將要實現的功能進行簡單說明。
  2. FIXME: 該處程式碼執行沒問題,但可能由於時間趕或者其他原因,需要修正。此時需要對如何修正進行簡單說明。
  3. HACK: 為修正某些問題而寫的不太好或者使用了某些詭異手段的程式碼。此時需要對思路或詭異手段進行描述。
  4. XXX: 該處存在陷阱。此時需要對陷阱進行描述。

3 語言特性

3.1 變數

  1. [強制] 變數、函式在使用前必須先定義。(注: 不通過 var 定義變數將導致變數汙染全域性環境。原則上不建議使用全域性變數,)

示例

// good
var name = 'MyName';

// bad
name = 'MyName';
複製程式碼
  1. [強制] 每個 var 只能宣告一個變數。(注:一個 var 宣告多個變數,容易導致較長的行長度,並且在修改時容易造成逗號和分號的混淆。)

示例

// good
var hangModules = [];
var missModules = [];
var visited = {};

// bad
var hangModules = [],
    missModules = [],
    visited = {};
複製程式碼
  1. [強制] 變數必須 即用即宣告,不得在函式或其它形式的程式碼塊起始位置統一宣告所有變數。(注: 變數宣告與使用的距離越遠,出現的跨度越大,程式碼的閱讀與維護成本越高。雖然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;
}
複製程式碼

3.2 條件

  1. [強制] 在 Equality Expression 中使用型別嚴格的 ===。僅當判斷 null 或 undefined 時,允許使用 == null。(注: 使用 === 可以避免等於判斷中隱式的型別轉換。)

示例

// good
if (age === 30) {
  // ......
}

// bad
if (age == 30) {
  // ......
}
複製程式碼
  1. [建議] 儘可能使用簡潔的表示式。

示例

// 字串為空

// 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. [建議] 對於相同變數或表示式的多值條件,用 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') {
    // ......
}
複製程式碼
  1. [建議] 如果函式或全域性中的 else 塊後沒有任何語句,可以刪除 else。

示例

// good
function getName() {
  if (name) {
    return name;
  }

  return 'unnamed';
}

// bad
function getName() {
  if (name) {
    return name;
  }
  else {
    return 'unnamed';
  }
}
複製程式碼

3.3 迴圈

  1. [建議] 不要在迴圈體中包含函式表示式,事先將函式提取到迴圈體外。(注: 迴圈體中的函式表示式,執行過程中會生成迴圈次數個函式物件。)

示例

// 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 () {});
}
複製程式碼
  1. [建議] 對迴圈內多次使用的不變值,在迴圈外用變數快取。

示例

// 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';
  // ......
}
複製程式碼
  1. [建議] 對有序集合進行遍歷時,快取 length。(注: 雖然現代瀏覽器都對陣列長度進行了快取,但對於一些宿主物件和老舊瀏覽器的陣列物件,在每次 length 訪問時會動態計算元素個數,此時快取 length 能有效提高程式效能。)

示例

// good
for (var i = 0, len = elements.length; i < len; i++) {
  var element = elements[i];
  // ......
}
複製程式碼

3.4 型別

3.4.1 型別檢測

[建議] 型別檢測優先使用 typeof。物件型別檢測使用 instanceof。null 或 undefined 的檢測使用 == null。

示例

// string
typeof variable === 'string'

// number
typeof variable === 'number'

// boolean
typeof variable === 'boolean'

// Function
typeof variable === 'function'

// Object
typeof variable === 'object'

// RegExp
variable instanceof RegExp

// Array
variable instanceof Array

// null
variable === null

// null or undefined
variable == null

// undefined
typeof variable === 'undefined'
複製程式碼

3.4.2 型別轉換

  1. [建議] 轉換成 string 時,使用 + ''。

示例

// good
num + '';

// bad
new String(num);
num.toString();
String(num);
複製程式碼
  1. [建議] 轉換成 number 時,通常使用 +。

示例

// good
+str;

// bad
Number(str);
複製程式碼
  1. [建議] string 轉換成 number,要轉換的字串結尾包含非數字並期望忽略時,使用 parseInt。

示例

var width = '200px';
parseInt(width, 10);
複製程式碼
  1. [強制] 使用 parseInt 時,必須指定進位制。

示例

// good
parseInt(str, 10);

// bad
parseInt(str);
複製程式碼

3.5 字串

  1. [強制] 字串開頭和結束使用單引號 '。(注: 實際使用中,字串經常用來拼接 HTML。為方便 HTML 中包含雙引號而不需要轉義寫法。)

示例

var str = '我是一個字串';
var html = '<div class="cls">拼接HTML可以省去雙引號轉義</div>';
複製程式碼

3.6 物件

  1. [強制] 使用物件字面量 {} 建立新 Object。

示例

// good
var obj = {};

// bad
var obj = new Object();
複製程式碼
  1. [建議] for in 遍歷物件時, 使用 hasOwnProperty 過濾掉原型中的屬性。

示例

var newInfo = {}
for (var key in info) {
  if(info.hasOwnProperty(key)){
    newInfo[key] = info[key];
  }
}
複製程式碼

3.7 陣列

  1. [強制] 使用陣列字面量 [] 建立新陣列,除非想要建立的是指定長度的陣列。

示例

// good
var arr = [];

// bad
var arr = new Array();
複製程式碼
  1. [強制] 遍歷陣列不使用 for in(注:陣列物件可能存在數字以外的屬性, 這種情況下 for in 不會得到正確結果。)

示例

var arr = ['a', 'b', 'c'];

// 這裡僅作演示, 實際中應使用 Object 型別
arr.other = 'other things';

// 正確的遍歷方式
for (var i = 0, len = arr.length; i < len; i++) {
  console.log(i);
}

// 錯誤的遍歷方式
for (var i in arr) {
  console.log(i);
}
複製程式碼

3.8 函式

3.8.1 函式長度

[建議] 一個函式的長度控制在 50 行以內。(注:將過多的邏輯單元混在一個大函式中,易導致難以維護。一個清晰易懂的函式應該完成單一的邏輯單元。複雜的操作應進一步抽取,通過函式的呼叫來體現流程。)

3.8.2 引數設計

  1. [建議] 一個函式的引數控制在 6 個以內,過多引數會導致維護難度增大。
  2. [建議] 通過 options 引數傳遞非資料輸入型引數。

相關文章