ES6 實踐規範

前言:團隊基於ES6和Eslint規則規定代碼規範,本文的目的是梳理和總結團隊如今實行的規範。javascript

做者:鄭靈華,點餐秒付終端團隊成員java

目錄

1、Eslint檢測ES6規範配置

  1. 編碼格式規範
  2. 聲明惟一性
  3. 初始化定義規範
  4. 代碼編寫注意事項
  5. 派生類相關

2、Airbnb規範節選

  1. 箭頭函數
  2. 構造器
  3. 迭代遍歷
  4. 屬性定義
  5. 解構
  6. 函數

3、參考資料


1、Eslint檢測ES6規範配置

1. 編碼格式規範

a.規定箭頭函數強制大括號
b.規定箭頭函數參數是否要使用括號
c.規定箭頭函數的箭頭先後的空格規範
d.generator 函數中 號周圍的空格
e.規定rest參數和擴展運算符與他們的參數之間的空格
f.禁止模板字面量中的花括號出現括號
g.強制在 yield
表達式中 * 後面使用空格git


a.規定箭頭函數強制大括號es6

//Eslint文件配置項
'arrow-body-style': ['error', 'as-needed', {
    requireReturnForObjectLiteral: false,
}]複製代碼
參數 參數說明 備註
as-needed 當大括號是可省略的,強制不使用
requireReturnForObjectLiteral 不須要顯式返回對象字面量 必須與as-needed 搭配使用
//項目中正確使用事例
//能夠省略大括號
let foo = () => 0; 
//不用顯式返回對象字面量
let foo = () => ({ bar: 0 });

//錯誤對比:
let foo = () => {
    return ({bar: 0 });
};複製代碼

b.規定箭頭函數參數是否要使用括號github

//Eslint文件配置項
'arrow-parens': ['error', 'as-needed', {
    requireForBlockBody: true,
}]複製代碼
參數 參數說明 備註
as-needed 當只有一個參數時容許省略圓括號
requireForBlockBody 當函數體在一個指令塊中,參數必須用圓括號包含 做爲as-needed補充。以函數體是否被 { } 包括快速判斷
//項目實踐正確例子
// 只有一個參數容許省略
a.map(x => {
  return x * x;
});
// requireForBlockBody 參數做爲補充,上述代碼修改爲
a.map((x) => {
  return x * x;
});複製代碼

c.箭頭函數的箭頭先後的空格規範數組

'arrow-spacing': ['error', { 
    before: true, 
    after: true 
}]複製代碼
參數 參數說明 備註
before 箭頭前面有空格
after 箭頭後面有空格
//項目應用
a => a;複製代碼

d.generator 函數中 * 號周圍的空格數據結構

'generator-star-spacing': ['error', { 
    before: false, 
    after: true 
}]複製代碼
參數 參數說明 備註
before *前面沒有空格
after *後面有空格
//項目正確使用示例
function* generator() {}複製代碼

e.不容許rest參數和擴展運算符與他們的參數之間有空格app

'rest-spread-spacing': ['error', 'never']複製代碼
參數 參數說明 備註
never 符號和參數之間不能有空格
//rest參數
let [a, b, ...arr] = [1, 2, 3, 4, 5]
//擴展運算符
function fn(){}
fn(...args)複製代碼

f.禁止模板字面量中的花括號出現括號less

'template-curly-spacing': 'error'複製代碼
//花括號裏面沒有括號
`hello, ${people.name}!`複製代碼

g.強制在 yield 表達式中 後面使用空格curl

'yield-star-spacing': ['error', 'after']複製代碼
function* generator() {
  yield* other();
}複製代碼

2. 聲明惟一性

a.不能修改類聲明的變量
b.禁止修改const聲明的變量
c.不容許類成員裏有重複的名稱
d.不要重複引入一個模塊
e.禁止在import,export,解構賦值中重命名和原有名字相同


a.不能修改類聲明的變量

'no-class-assign': 'error'複製代碼
// 簡而言之,若是以class Name{}形object-shorthand式出現,那麼Name不能作任何更改和賦值
// 下面例子是正確的。由於A至始至終只是變量
let A = class {
    b() {
        A = 0; 
        console.log(A);
    }
}
console.log(A); //class
let Foo = new A(); 
Foo.b(); //0
console.log(A); //0複製代碼

b.禁止修改const聲明的變量

'no-const-assign': 'error'複製代碼

c.不容許類成員裏有重複的名稱

'no-dupe-class-members': 'error'複製代碼

d.不要重複引入一個模塊

'no-duplicate-imports': 'off'複製代碼
//同一個模塊引入兩個變量應該寫在一個大括號裏面
import { merge, find } from 'module';複製代碼

e.禁止在import,export,解構賦值中重命名和原有名字相同

'no-useless-rename': ['error', {
  ignoreDestructuring: false,
  ignoreImport: false,
  ignoreExport: false,
}]複製代碼
//形如{ foo as foo }和{ bar: bar }並無起到重命名的做用,因此應該禁止這種冗餘書寫
import { foo as bar } from "baz";
export { foo as bar } from "foo";
let { [foo]: foo } = bar;複製代碼

3. 初始化定義規範

a.Symbol類型不能用new關鍵字
b.Symbol定義的時候增長描述語言,便於debug
c.generator函數裏面必定要有yield
d.使用 let 或 const 而不是 var
e.禁止在字面量聲明無用的計算屬性
f.若變量不會再次賦值,使用const聲明


a.Symbol類型不能用new關鍵字

'no-new-symbol': 'error'複製代碼
//symbol應該以函數形式調用
var foo = Symbol('foo');複製代碼

b.Symbol定義的時候增長描述語言,便於debug

'symbol-description': 'error'複製代碼
let foo = Symbol("some description")複製代碼

c.generator函數裏面必定要有yield

'require-yield': 'error'複製代碼

d.使用 let 或 const 而不是 var

'no-var': 'error'複製代碼

e.禁止在字面量聲明無用的計算屬性

'no-useless-computed-key': 'error'複製代碼
//無用的["a"]計算屬性
var foo = {['0+1,234']: "b"};

//改寫成
var foo = { '0+1,234': 0 };複製代碼

f.若變量不會再次賦值,使用const聲明

'prefer-const': ['error', {
  destructuring: 'any',
  ignoreReadBeforeAssign: true,
}]複製代碼
參數 參數說明 備註
destructuring 解構賦值時,全部變量的類型都應該保持一致
ignoreReadBeforeAssign 忽略聲明和第一次賦值之間的變量 也就是不能先定義後賦值
//解構賦值時,值要麼都是const要麼都是let
// a0是肯定的,b沒有被賦值
const {a: a0, b} = obj;
const a = a0 + 1;

// a,b都是變量,因此解構賦值定義用let
let {a, b} = obj;
a = a + 1;
b = b + 1;

//錯誤例子,在ignoreReadBeforeAssign=true時,timer的聲明和賦值之間的initialize()函數聲明會被省略。
//從而會在setInterval處報錯函數undefined
let timer;
function initialize() {
    if (foo()) {
        clearInterval(timer);
    }
}
timer = setInterval(initialize, 100);

//正確例子,只要聲明就要賦值!
const timer = setInterval(initialize, 100);
function initialize() {
    if (foo()) {
        clearInterval(timer);
    }
}複製代碼

4.代碼編寫注意事項

a. 避免箭頭函數和比較式混淆
b. 使用模板字面量而不是字符串拼接
c. 使用擴展運算符(...)而非.apply()調用可變參數
d. 用rest參數(...變量名)替換arguments
e. 不容許使用parseInt()轉化2,8,16進制
f. 要求使用箭頭函數進行回調
g. 對象字面量語法簡寫


a.避免箭頭函數和比較式混淆

'no-confusing-arrow': ['error', {
    allowParens: true,
}]複製代碼
參數 參數說明 備註
allowParens 放寬標準,容許箭頭函數使用括號 不強制必須用return返回
//若是是嚴格模式,會發現即便用圓括號包含,也要用return區分箭頭函數和三元運算比較
var x = a => { return 1 ? 2 : 3; };
var x = (a) => { return 1 ? 2 : 3; };

//若是allowParens=true,則放寬標準
var x = a => (1 ? 2 : 3);
var x = (a) => (1 ? 2 : 3);複製代碼

b.使用模板字面量而不是字符串拼接

'prefer-template': 'error'複製代碼
let str = `Hello, ${name}!`複製代碼

c.使用擴展運算符(...)而非.apply()調用可變參數

'prefer-spread': 'error'複製代碼
//求出一個數組最大元素
Math.max.apply(null, [14, 3, 77])
//等效於
Math.max(...[14, 3, 77])
//等同
Math.max(14, 3, 77)複製代碼

d.用rest參數(...變量名)替換arguments

'prefer-rest-params': 'error'複製代碼
//rest運算符能夠提供一個真正的數組,能顯式表示參數
//而arguments是一個對象,操做中要經過call等手段調用數組方法
function foo(...args) {
    console.log(args);
}複製代碼

e. 不容許使用parseInt()轉化2,8,16進制

'prefer-numeric-literals': 'error'複製代碼
//只針對2,8,16進制使用
//數字轉化成其餘進制或者是變量轉化仍是用parseInt
0b111110111 === 503;
0o767 === 503;
0x1F7 === 503;

parseInt(1, 3);
parseInt(foo, 2);複製代碼

f. 要求使用箭頭函數進行回調

'prefer-arrow-callback': ['error', {
  allowNamedFunctions: false,
  allowUnboundThis: true,
}]複製代碼
參數 參數說明 備註
allowNamedFunctions 若是回調函數裏面是命名函數則報錯
allowUnboundThis 不使用bind()指定this,規則會動態標記this的使用
//直接使用this,而不是bind(this)
//回調函數裏是匿名函數
foo(function() { return this.a; });複製代碼

g.對象字面量語法簡寫

'object-shorthand': ['error', 'always', {
  ignoreConstructors: false,
  avoidQuotes: true,
}]複製代碼
參數 參數說明 備註
always 能簡寫就簡寫
ignoreConstructors 構造函數不能省略 必須指定第一個參數
avoidQuotes 對象鍵是字符串時,用長格式 必須指定第一個參數
// 由於foo對象兩個鍵都是string,因此後面不能省略
var foo = {
    "bar-baz": function() {},
    "qux": qux
}複製代碼

5.派生類相關

a. 構造函數必須調用 super
b. 禁止沒必要要的構造函數
c. 派生類函數構造器禁止在super()以前使用this


a. 構造函數必須調用 super

'constructor-super': 'error'複製代碼
//派生類中構造函數必須調用,非派生類的構造函數不能調用super()
class A {
    constructor() { }
}

class A extends B {
    constructor() {
        super();
    }
}複製代碼

b. 禁止沒必要要的構造函數

'no-useless-constructor': 'error'複製代碼
//簡單講即是構造器裏面必定要有執行的邏輯代碼
class A {
    constructor () {
        doSomething();
    }
}
//若是沒有特別的邏輯,則類返回空便可
class A { }複製代碼

c. 派生類函數構造器禁止在super()以前使用this

'no-this-before-super': 'error複製代碼
//不然會返回引用錯誤(reference error)
class A extends B {
    constructor() {
        super();
        this.a = 0; // OK, this is after `super()`.
    }
}複製代碼

2、Airbnb規範節選

1. 箭頭函數

  • 當函數特別簡單,而且只有一個參數,可省略花括號、圓括號、return
  • 提升鏈式調用可讀性,不斷傳遞this
  • 可是結果須要回傳一個對象時,不能省略return

2. 構造器

  • 用class替代prototype
//用class更爲簡潔
class Foo {
   constructor(){}
   getVal(){}  
}
//等價於
Foo.prototype = {
   getVal(){}
}複製代碼
  • 用extends實現繼承,不直接操做prototype
  • class能實現模塊開發,而且能經過返回this實現鏈式調用
  • 類的數據類型就是函數,類自己就指向構造函數
class Foo {}
typeof Foo;  // Function
Foo === Foo.prototype.constructor; //true複製代碼

3. 迭代遍歷

  • ES6提供的遍歷器Iterator,適合於部署了Symbol.iterator屬性的數據結構,能夠用for...of遍歷成員
  • for...in遍歷object全部可枚舉對象,包含當前對象和原型上
  • for...of遍歷collection對象,並不適用全部object,視乎其是否有[Symbol.iterator]屬性。且只遍歷當前對象
  • Airbnb推薦使用高階函數例如 map() 和 reduce() 替代 for-of,便於處理函數回調

4. 屬性定義

  • 若是對象具備動態屬性名,在一開始使用可計算的屬性名稱,保證全部屬性定義在一塊兒
const obj = {
  id: 5,
  name: 'San Francisco',
  [getKey('enabled')]: true,
}複製代碼

5. 解構

  • 推薦使用解構賦值,減小臨時變量的引入
  • 須要回傳多個值時,使用對象解構,而不是數組解構,方便調用時能夠忽略順序
// 數組解構=>調用時回調數據的順序是一一對應的
function processInput(input) {
  // then a miracle occurs
  return [left, right, top, bottom];
}
const [left, __, top] = processInput(input);

// 對象解構=>不考慮順序,只要保證變量必須與屬性同名
function processInput(input) {
  // then a miracle occurs
  return { left, right, top, bottom };
}
const { left, right } = processInput(input);複製代碼
  • 對象的解構賦值的內部機制,是先找到同名屬性,而後再賦給對應的變量。真正被賦值的是後者,而不是前者。
let { foo: baz } = { foo: "aaa", bar: "bbb" };
baz; // "aaa"
foo; // error: foo is not defined複製代碼

6. 函數

  • 使用函數聲明代替函數表達式,便於在調用棧識別,避免整個函數被提高。同時,箭頭函數能夠取代函數表達式
  • 不要把參數命名爲 arguments。這將取代原來函數做用域內的 arguments 對象
  • 不要使用 arguments。用 rest 語法 ... 替代
  • 推薦: 函數參數應該指定默認值
//bad code,若是是Boolean,傳進去甚至會改變opts的類型
function handleThings(opts) {
   opts = opts || {};
}
//Airbnb 推薦寫法,初始化參數
function handleThings(opts = {}) {}複製代碼

3、參考資料

Airbnb JavaScript規範
阮一峯-ES6入門教程
小問ES6理解-進階版
ES6 In Depth (深刻淺出ES6)

相關文章
相關標籤/搜索