ES2015 代码规范
综述
- 本文翻译自 Airbnb 推荐的 Javascript 编码规范 – ES6,原文地址如下:
 
Arrow Functions 箭头函数
- 使用箭头函数代替匿名函数
箭头函数使得 this 的值不会发生你不想要的改变
 
  // bad
  [1, 2, 3].map(function (x) {
     const y = x + 1;
     return x * y;
  });
  // good
  [1, 2, 3].map((x) => {
     const y = x + 1;
     return x * y;
  });
如果函数体只包含一个表达式,那么省略表达式的大括号并且使用隐式的 return,否则加上
return// good [1, 2, 3].map(number => `A string containing the ${number}.`); // bad [1, 2, 3].map(number => { const nextNumber = number + 1; `A string containing the ${nextNumber}.`; }); // good [1, 2, 3].map(number => { const nextNumber = number + 1; return `A string containing the ${nextNumber}.`; });如果表达式需要多行显示,则用小括号包起来
// bad [1, 2, 3].map(number => 'As time went by, the string containing the ' + `${number} became much longer. So we needed to break it over multiple ` + 'lines.' ); // good [1, 2, 3].map(number => ( `As time went by, the string containing the ${number} became much ` + 'longer. So we needed to break it over multiple lines.' ));如果函数只有一个变量,则省略小括号
// good [1, 2, 3].map(x => x * x); // good [1, 2, 3].reduce((y, x) => x + y);
Constructors 构造函数
总是使用
class,避免直接操作prototype// bad function Queue(contents = []) { this._queue = [...contents]; } Queue.prototype.pop = function() { const value = this._queue[0]; this._queue.splice(0, 1); return value; } // good class Queue { constructor(contents = []) { this._queue = [...contents]; } pop() { const value = this._queue[0]; this._queue.splice(0, 1); return value; } }使用
extends来继承// bad const inherits = require('inherits'); function PeekableQueue(contents) { Queue.apply(this, contents); } inherits(PeekableQueue, Queue); PeekableQueue.prototype.peek = function() { return this._queue[0]; } // good class PeekableQueue extends Queue { peek() { return this._queue[0]; } }方法可以返回
this,方便链式调用// bad Jedi.prototype.jump = function() { this.jumping = true; return true; }; Jedi.prototype.setHeight = function(height) { this.height = height; }; const luke = new Jedi(); luke.jump(); // => true luke.setHeight(20); // => undefined // good class Jedi { jump() { this.jumping = true; return this; } setHeight(height) { this.height = height; return this; } } const luke = new Jedi(); luke.jump() .setHeight(20);自定义
toString()方法,可以返回自己想要的结果class Jedi { constructor(options = {}) { this.name = options.name || 'no name'; } getName() { return this.name; } toString() { return `Jedi - ${this.getName()}`; } }
对象方法缩写
// bad
const atom = {
  value: 1,
  addValue: function (value) {
    return atom.value + value;
  },
};
// good
const atom = {
  value: 1,
  addValue(value) {
    return atom.value + value;
  },
};
属性和值一样时,可以缩写
  const lukeSkywalker = 'Luke Skywalker';
  // bad
  const obj = {
    lukeSkywalker: lukeSkywalker,
  };
  // good
  const obj = {
    lukeSkywalker,
  };
支持动态属性名
  function getKey(k) {
   return `a key named ${k}`;
 }
 // bad
 const obj = {
   id: 5,
   name: 'San Francisco',
 };
 obj[getKey('enabled')] = true;
 // good
 const obj = {
   id: 5,
   name: 'San Francisco',
   [getKey('enabled')]: true,
 };
模板字符串
  // bad
  function sayHi(name) {
    return 'How are you, ' + name + '?';
  }
  // bad
  function sayHi(name) {
    return ['How are you, ', name, '?'].join();
  }
  // good
  function sayHi(name) {
    return `How are you, ${name}?`;
  }
Destructuring 解构
使用一个对象的多个属性时,使用解构来获取
// bad function getFullName(user) { const firstName = user.firstName; const lastName = user.lastName; return `${firstName} ${lastName}`; } // good function getFullName(obj) { const { firstName, lastName } = obj; return `${firstName} ${lastName}`; } // best function getFullName({ firstName, lastName }) { return `${firstName} ${lastName}`; }使用数组解构
const arr = [1, 2, 3, 4]; // bad const first = arr[0]; const second = arr[1]; // good const [first, second] = arr;多值返回时使用对象解构而不是数组解构
这样可以随时添加新的属性以及修改属性的顺序,不需要做其他的改动
  // bad
  function processInput(input) {
    // then a miracle occurs
    return [left, right, top, bottom];
  }
  // the caller needs to think about the order of return data
  const [left, __, top] = processInput(input);
  // good
  function processInput(input) {
    // then a miracle occurs
    return { left, right, top, bottom };
  }
  // the caller selects only the data they need
  const { left, right } = processInput(input);
Default Parameters 参数默认值
使用参数默认值,而不是去改变参数
// really bad function handleThings(opts) { // No! We shouldn't mutate function arguments. // Double bad: if opts is falsy it'll be set to an object which may // be what you want but it can introduce subtle bugs. opts = opts || {}; // ... } // still bad function handleThings(opts) { if (opts === void 0) { opts = {}; } // ... } // good function handleThings(opts = {}) { // ... }避免默认参数带来的副作用
var b = 1; // bad function count(a = b++) { console.log(a); } count(); // 1 count(); // 2 count(3); // 3 count(); // 3总是把默认参数放在最后
// bad function handleThings(opts = {}, name) { // ... } // good function handleThings(name, opts = {}) { // ... }
rest
- 使用 
...替代argumentsrest 参数是一个真正的数组,而 arguments 是一个类数组
 
  // bad
  function concatenateAll() {
    const args = Array.prototype.slice.call(arguments);
    return args.join('');
  }
  // good
  function concatenateAll(...args) {
    return args.join('');
  }
- 使用 
...来复制数组// bad const len = items.length; const itemsCopy = []; let i; for (i = 0; i < len; i++) { itemsCopy[i] = items[i]; } // good const itemsCopy = [...items]; 
const 和 let
- 使用 
const来定义所有的引用const 保证你不能改变你的引用,从而导致未知的 bug
 
  // bad
  var a = 1;
  var b = 2;
  // good
  const a = 1;
  const b = 2;
使用
let定义变量// bad var count = 1; if (true) { count += 1; } // good, use the let. let count = 1; if (true) { count += 1; }变量定义
const和let都拥有块级作用域// const and let only exist in the blocks they are defined in. { let a = 1; const b = 1; } console.log(a); // ReferenceError console.log(b); // ReferenceError
Iterators and Generators
- 不要使用迭代器,使用 
map(),reduce(),forEach()等替代for-of循环语句const numbers = [1, 2, 3, 4, 5]; // bad let sum = 0; for (let num of numbers) { sum += num; } sum === 15; // good let sum = 0; numbers.forEach((num) => sum += num); sum === 15; // best (use the functional force) const sum = numbers.reduce((total, num) => total + num, 0); sum === 15; 
Modules 模块
从现在开始,使用
import/export// bad const AirbnbStyleGuide = require('./AirbnbStyleGuide'); module.exports = AirbnbStyleGuide.es6; // ok import AirbnbStyleGuide from './AirbnbStyleGuide'; export default AirbnbStyleGuide.es6; // best import { es6 } from './AirbnbStyleGuide'; export default es6;不要 import 通配符
// bad import * as AirbnbStyleGuide from './AirbnbStyleGuide'; // good import AirbnbStyleGuide from './AirbnbStyleGuide';不要直接从 export 一个 import 表达式
// bad // filename es6.js export { es6 as default } from './airbnbStyleGuide'; // good // filename es6.js import { es6 } from './AirbnbStyleGuide'; export default es6;