ESLint 代码检查规范

目录

Airbnb Javascript Style Guide

  1. 引用
  2. 对象
  3. 数组
  4. 函数
  5. 箭头函数
  6. 类和构造器
  7. 模块
  8. Iterators and Generators
  9. 变量
  10. 比较运算符
  11. 注释
  12. 空格

Airbnb React/JSX Style Guide

  1. 基本规范
  2. Class vs React.createClass vs stateless
  3. 命名
  4. 声明模块
  5. 代码对齐
  6. 引号
  7. 空格
  8. 属性
  9. Refs
  10. 括号
  11. 标签
  12. 函数/方法
  13. 模块生命周期
  14. isMounted

Airbnb Javascript Style Guide

引用

  • 对全部的引用使用 const ,不要使用 var. eslint: prefer-const, no-const-assign
    这能确保你没法对引用从新赋值,也不会致使出现 bug 或难以理解
// bad
  var a = 1;
  var b = 2;

// good
 const a = 1;
 const b = 2;
  • 若是必定须要可变更的引用,使用 let 代替 var. eslint: no-var jscs: disallowVar
    由于 let 是块级做用域,而 var 是函数做用域。
// bad
  var count = 1;
  if (true) {
    count += 1;
  }

  // good, use the let.
  let count = 1;
  if (true) {
    count += 1;
  }

⬆ 回到顶部javascript

对象

// bad
const item = new Object();

// good
const item = {};
  • 使用动态属性名称建立对象时,请使用计算属性名称

为何? 它们容许你在一个位置定义对象的全部属性html

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
const atom = {
  value: 1,

  addValue: function (value) {
    return atom.value + value;
  },
};

// good
const atom = {
  value: 1,

  addValue(value) {
    return atom.value + value;
  },
};
  • 使用对象属性值的简写。eslint: object-shorthand
    这样更短更有描述性。
const lukeSkywalker = 'Luke Skywalker';

  // bad
  const obj = {
    lukeSkywalker: lukeSkywalker,
  };

  // good
  const obj = {
    lukeSkywalker,
  };
  • 把 你声明的对象 的 简写属性 和 非简写属性 分组

为何? 更容易知道哪些属性用了简写java

const anakinSkywalker = 'Anakin Skywalker';
const lukeSkywalker = 'Luke Skywalker';

// bad
const obj = {
  episodeOne: 1,
  twoJediWalkIntoACantina: 2,
  lukeSkywalker,
  episodeThree: 3,
  mayTheFourth: 4,
  anakinSkywalker,
};

// good
const obj = {
  lukeSkywalker,
  anakinSkywalker,
  episodeOne: 1,
  twoJediWalkIntoACantina: 2,
  episodeThree: 3,
  mayTheFourth: 4,
};

为何?通常来讲咱们主观上认为它更容易阅读。它改进了高亮语法,而且更容易被许多JS引擎优化node

// bad
const bad = {
  'foo': 3,
  'bar': 4,
  'data-blah': 5,
};

// good
const good = {
  foo: 3,
  bar: 4,
  'data-blah': 5,
};
  • 不要直接调用 Object.prototype 的方法,如:hasOwnProperty, propertyIsEnumerable, 和 isPrototypeOf

为何? 这些方法可能被 有问题的对象属性 隐藏 - 考虑{hasOwnProperty: false} - 或者, 对象多是一个空对象(Object.create(null)react

// bad
console.log(object.hasOwnProperty(key));

// good
console.log(Object.prototype.hasOwnProperty.call(object, key));

// best
const has = Object.prototype.hasOwnProperty; // cache the lookup once, in module scope.
/* or */
const has = require('has');
…
console.log(has.call(object, key));
  • 浅拷贝对象的时候最好是使用 … 操做符而不是 Object.assign
// very bad
const original = { a: 1, b: 2 };
const copy = Object.assign(original, { c: 3 }); // this mutates `original`  ಠ_ಠ
delete copy.a; // so does this

// bad
const original = { a: 1, b: 2 };
const copy = Object.assign({}, original, { c: 3 }); // copy => { a: 1, b: 2, c: 3 }

// good
const original = { a: 1, b: 2 };
const copy = { ...original, c: 3 }; // copy => { a: 1, b: 2, c: 3 }

const { a, ...noA } = copy; // noA => { b: 2, c: 3 }

⬆ 回到顶部git

数组

// bad
const items = new Array();

// good
const items = [];
  • 数组添加元素时,使用push 代替 直接赋值
const someStack = [];

// bad
someStack[someStack.length] = 'abracadabra';

// good
someStack.push('abracadabra');
  • 使用拓展运算符 … 复制数组。
// bad
const items = new Array();

// good
const items = [];

// bad
const len = items.length;
const itemsCopy = [];
let i;

for (i = 0; i < len; i++) {
  itemsCopy[i] = items[i];
}

// good
const itemsCopy = [...items];
const foo = document.querySelectorAll('.foo');
const nodes = Array.from(foo);

⬆ 回到顶部es6

函数

  • 使用命名函数表达式,而不是函数声明。eslint: func-stylegithub

    为何?函数声明是可被提高的, 这意味着太容易在 函数被定义以前 就引用它了。这会损害可读性和可维护性。若是你发现一个函数的定义是复杂的以至于它干扰到其他文件,,那么该提取成独立的模块。不要忘记命名表达式 - 匿名函数会使得更难在 Error's call stack 中找到问题(Discussion)ajax

// bad
const foo = function () {
};

// bad
function foo() {
}

// good
const foo = function bar() {
};
  • 用括号包装函数表达式成为 当即调用函数表达式(Wrap immediately invoked function expressions in parentheses.)。eslint: wrap-iife

为何?一个当即调用的表达式是一个单一的单元express

// 当即调用的函数表达式 (IIFE)
(() => {
   console.log('Welcome to the Internet. Please follow me.');
})();
  • 永远不要在一个非函数代码块(if、while 等)中声明一个函数。把那个函数赋给一个变量。浏览器容许你这么作,但它们的解析表现不一致. eslint: no-loop-func

  • 注意:ECMA-262 将 block 定义为语句列表 。 函数声明不是语句,Read ECMA-262's note on this issue.

// bad
if (currentUser) {
  function test() {
    console.log('Nope.');
  }
}

// good
let test;
if (currentUser) {
  test = () => {
    console.log('Yup.');
  };
}
  • 不要把参数命名为arguments ,这将形成优先覆盖原来每一个给定做用域的arguments
// bad
function nope(name, options, arguments) {
  // ...stuff...
}

// good
function yup(name, options, args) {
  // ...stuff...
}
  • 不要使用 arguments。能够选择 rest 语法 … 替代。 eslint: prefer-rest-params

    为何?使用 … 能明确你要传入的参数。另外 rest 参数是一个真正的数组,而 arguments 是一个类数组。

// bad
  function concatenateAll() {
    const args = Array.prototype.slice.call(arguments);
    return args.join('');
  }

  // good
  function concatenateAll(...args) {
    return args.join('');
  }
  • 使用默认参数语法,而不是改变函数参数
// 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 = {}) {
  // ...
}
  • 老是把默认参数放在最后
// bad
function handleThings(opts = {}, name) {
  // ...
}

// good
function handleThings(name, opts = {}) {
  // ...
}

为何? 操做做为参数传递的对象可能会在原始调用者中形成没必要要的变量反作用。

// bad
function f1(obj) {
  obj.key = 1;
};

// good
function f2(obj) {
  const key = Object.prototype.hasOwnProperty.call(obj, 'key') ? obj.key : 1;
};

为何? 从新分配参数可能会致使 unexpected behavior, 特别是仇敌访问arguments对象的时候。它也可能致使优化问题,特别是在V8。

// bad
function f1(a) {
  a = 1;
}

function f2(a) {
  if (!a) { a = 1; }
}

// good
function f3(a) {
  const b = a || 1;
}

function f4(a = 1) {
}

⬆ 回到顶部

箭头函数

  • 当你必须使用函数表达式(或传递一个匿名函数)时,使用箭头函数符号。eslint: prefer-arrow-callback, arrow-spacing

    为何?由于箭头函数创造了新的一个 this 执行环境(译注:参考 Arrow functions - JavaScript | MDN 和 ES6 arrow functions, syntax and lexical scoping),一般状况下都能知足你的需求,并且这样的写法更为简洁。
    为何不?若是你有一个至关复杂的函数,你或许能够把逻辑部分转移到一个函数声明上。

// bad
  [1, 2, 3].map(function (x) {
    return x * x;
  });

  // good
  [1, 2, 3].map((x) => {
    return x * x;
  });
// bad
[1, 2, 3].map(number => {
  const nextNumber = number + 1;
  `A string containing the ${nextNumber}.`;
});

// good
[1, 2, 3].map(number => `A string containing the ${number}.`);

// good
[1, 2, 3].map((number) => {
  const nextNumber = number + 1;
  return `A string containing the ${nextNumber}.`;
});

// good
[1, 2, 3].map((number, index) => ({
  [index]: number
}));
  • 以防表达式过长,利用括号让代码可读性更好

    为何? 它能更清晰的展现函数的starts 和 ends.

// bad
['get', 'post', 'put'].map(httpMethod => Object.prototype.hasOwnProperty.call(
    httpMagicObjectWithAVeryLongName,
    httpMethod
  )
);

// good
['get', 'post', 'put'].map(httpMethod => (
  Object.prototype.hasOwnProperty.call(
    httpMagicObjectWithAVeryLongName,
    httpMethod
  )
));
  • 避免混淆箭头函数语法(=>)和比较运算符(<=, >=). eslint: no-confusing-arrow
// bad
const itemHeight = item => item.height >= 256 ? item.largeSize : item.smallSize;

// bad
const itemHeight = (item) => item.height >= 256 ? item.largeSize : item.smallSize;

// good
const itemHeight = item => (item.height >= 256 ? item.largeSize : item.smallSize);

// good
const itemHeight = (item) => {
  const { height, largeSize, smallSize } = item;
  return height >= 256 ? largeSize : smallSize;
};

⬆ 回到顶部

类和构造器

  • 老是使用 class。避免直接操做 prototype

    为何? 由于 class 语法更为简洁更易读。

// 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 继承。

    为何?由于 extends 是一个内建的原型继承方法而且不会破坏 instanceof。

// 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);
  • 避免重复的类成员

为何? 重复声明类成员,那只会承认最后一个。 - having duplicates is almost certainly a bug.

// bad
class Foo {
  bar() { return 1; }
  bar() { return 2; }
}

// good
class Foo {
  bar() { return 1; }
}

// good
class Foo {
  bar() { return 2; }
}

⬆ 回到顶部

模块

  • 老是使用import/export

    Why? Modules are the future, let's start using the future now.

// 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的时候不要使用通配符

    为何?这样能确保你只有一个默认 export。

// bad
  import * as AirbnbStyleGuide from './AirbnbStyleGuide';

  // good
  import AirbnbStyleGuide from './AirbnbStyleGuide';
  • 不要从 import 中直接 export

    为何?虽然一行代码简洁明了,但让 import 和 export 各司其职让事情能保持一致。

// bad
  // filename es6.js
  export { es6 as default } from './airbnbStyleGuide';

  // good
  // filename es6.js
  import { es6 } from './AirbnbStyleGuide';
  export default es6;
  • import同一路径的,就一次性引入。eslint: no-duplicate-imports

    为何?从同一路径导入多个行可能会使代码难以维护。

// bad
  import foo from 'foo';
  // … some other imports … //
  import { named1, named2 } from 'foo';

  // good
  import foo, { named1, named2 } from 'foo';

  // good
  import foo, {
    named1,
    named2,
  } from 'foo';
  • 不要export可变的绑定。eslint: import/no-mutable-exports

    为何? 应该避免突变,通常来讲,但特别是当输出可变绑定。 虽然在某些特殊状况下可能须要此技术,但通常来讲,只应导出常量引用。

// bad
  let foo = 3;
  export { foo }

  // good
  const foo = 3;
  export { foo }
// bad
  export function foo() {}

  // good
  export default function foo() {}
  • 将全部导入都放在非import语句之上。 eslint: import/first

    为何? 保证他们一直在顶部能够预防 surprising behavior.

// bad
  import foo from 'foo';
  foo.init();

  import bar from 'bar';

  // good
  import foo from 'foo';
  import bar from 'bar';

  foo.init();

⬆ 回到顶部

Iterators and Generators

  • 不要使用 iterators,使用javascript的高阶函数例 替代for-in, for-of 。 eslint: no-iterator no-restricted-syntax

    为何?这强制咱们不变的规则。处理有返回值的纯函数比 处理它的反作用更容易。
    纯函数的回调值更易读,这比它带来的反作用更重要。
    Use map() / every() / filter() / find() / findIndex() / reduce() / some() / ... to iterate over arrays,
    and Object.keys() / Object.values() / Object.entries() to produce arrays so you can iterate over objects.

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;
  • 如今还不要使用 generators

    为何?由于它们如今还无法很好地编译到 ES5。 (目前Chrome 和 Node.js 的稳定版本都已支持 generators)

⬆ 回到顶部

变量

  • 一直使用 const 来声明变量。 若是不这样作就会产生全局变量。咱们须要避免全局命名空间的污染。eslint: generator-star-spacing
// bad
superPower = new SuperPower();

// good
const superPower = new SuperPower();
  • 使用 const 声明每个变量。eslint: one-var

    为何?增长新变量将变的更加容易,并且你永远不用再担忧调换错 ;, , 或引入仅标点符号差别。你还可使用debugger遍历每一个声明,而不是一次性跳过全部声明。

// bad
const items = getItems(),
    goSportsTeam = true,
    dragonball = 'z';

// bad
// (compare to above, and try to spot the mistake)
const items = getItems(),
    goSportsTeam = true;
    dragonball = 'z';

// good
const items = getItems();
const goSportsTeam = true;
const dragonball = 'z';
  • 将全部的 const 和 let 分组

    为何?当你须要把已赋值变量赋值给未赋值变量时很是有用。

// bad
  let i, len, dragonball,
      items = getItems(),
      goSportsTeam = true;

  // bad
  let i;
  const items = getItems();
  let dragonball;
  const goSportsTeam = true;
  let len;

  // good
  const goSportsTeam = true;
  const items = getItems();
  let dragonball;
  let i;
  let length;
  • 在你须要的地方给变量赋值,但请把它们放在一个合理的位置

    为何?let 和 const 是块级做用域而不是函数做用域。

// bad - unnecessary function call
function checkName(hasName) {
  const name = getName();

  if (hasName === 'test') {
    return false;
  }

  if (name === 'test') {
    this.setName('');
    return false;
  }

  return name;
}

// good
function checkName(hasName) {
  if (hasName === 'test') {
    return false;
  }

  const name = getName();

  if (name === 'test') {
    this.setName('');
    return false;
  }

  return name;
}
  • 不要连接变量赋值

    为何? 连接变量分配建立隐式全局变量。

// bad
(function example() {
  // JavaScript interprets this as
  // let a = ( b = ( c = 1 ) );
  // The let keyword only applies to variable a; variables b and c become
  // global variables.
  let a = b = c = 1;
}());

console.log(a); // undefined
console.log(b); // 1
console.log(c); // 1

// good
(function example() {
  let a = 1;
  let b = a;
  let c = a;
}());

console.log(a); // undefined
console.log(b); // undefined
console.log(c); // undefined

// the same applies for `const`
  • 避免使用一元增量和减量(++, --). eslint no-plusplus

    为何? 根据eslint文档,一元增量和减量语句受到自动分号插入的影响,而且可能会致使应用程序中的值递增或递减的无声错误。 使用num + = 1而不是num ++或num ++这样的语句来改变你的值也更具表现力。 不容许一元增量和减量语句也会阻止您无心地预先递增/预减量值,这也会致使程序出现unexpected behavior。

// bad

  let array = [1, 2, 3];
  let num = 1;
  num++;
  --num;

  let sum = 0;
  let truthyCount = 0;
  for(let i = 0; i < array.length; i++){
    let value = array[i];
    sum += value;
    if (value) {
      truthyCount++;
    }
  }

  // good

  let array = [1, 2, 3];
  let num = 1;
  num += 1;
  num -= 1;

  const sum = array.reduce((a, b) => a + b, 0);
  const truthyCount = array.filter(Boolean).length;

⬆ 回到顶部

比较运算符

  • 优先使用 === 和 !== 而不是 == 和 !=。 eslint: eqeqeq
  • 条件表达式例如 if 语句经过抽象方法 ToBoolean 强制计算它们的表达式而且老是遵照下面的规则:
    • 对象 被计算为 true
    • Undefined 被计算为 false
    • Null 被计算为 false
    • 布尔值 被计算为 布尔的值
    • 数字 若是是 +0、-0、或 NaN 被计算为 false, 不然为 true
    • 字符串 若是是空字符串 被计算为 false,不然为 true
if ([0] && []) {
  // true
  // an array (even an empty one) is an object, objects will evaluate to true
}
  • 判断布尔值的时候能够用简短写法,可是比较字符串和数字的时候就明确写
// bad
if (isValid === true) {
  // ...stuff...
}

// good
if (isValid) {
  // ...stuff...
}

// bad
if (name) {
  // ...stuff...
}

// good
if (name !== '') {
  // ...stuff...
}

// bad
if (collection.length) {
  // ...stuff...
}

// good
if (collection.length > 0) {
  // ...stuff...
}

⬆ 回到顶部

注释

  • 使用 /** ... */ 做为多行注释。包含描述、指定全部参数和返回值的类型和值
// bad
// make() returns a new element
// based on the passed in tag name
//
// @param {String} tag
// @return {Element} element
function make(tag) {

  // ...stuff...

  return element;
}

// good
/**
 * make() returns a new element
 * based on the passed in tag name
 *
 * @param {String} tag
 * @return {Element} element
 */
function make(tag) {

  // ...stuff...

  return element;
}
  • 使用 // 做为单行注释。在注释对象上面另起一行使用单行注释。在注释前插入空行
// bad
const a = 0;// 我是注释
 
// bad
//我是注释
const a = 0;
 
// good
// 我是注释
const a = 0;
  • 给注释增长 FIXME 或 TODO 的前缀
    帮助其余开发者快速了解这是一个须要复查的问题,或是给须要实现的功能提供一个解决方式。这将有别于常见的注释,由于它们是可操做的。使用 FIXME: -- need to figure this out or TODO: -- need to implement.

  • 使用 // FIXME: 标注问题
class Calculator {
  constructor() {
    // FIXME: shouldn't use a global here
    total = 0;
  }
}
  • 使用 // TODO: 标注问题的解决方式。
class Calculator {
  constructor() {
    // TODO: total should be configurable by an options param
    this.total = 0;
  }
}

⬆ 回到顶部

Whitespace

  • 使用 2 个空格做为缩进。 eslint: indent
  • 花括号前要放一个空格。eslint: space-before-blocks
  • 在控制语句(if、while 等)的小括号前放一个空格;在函数调用及声明中,不在函数的参数列表前加空格。eslint: keyword-spacing
  • 操做符两侧要有空格。eslint: space-infix-ops
// bad
const x=y+5;

// good
const x = y + 5;
// bad
$('#items').find('.selected').highlight().end().find('.open').updateCount();

// bad
$('#items').
  find('.selected').
    highlight().
    end().
  find('.open').
    updateCount();

// good
$('#items')
  .find('.selected')
    .highlight()
    .end()
  .find('.open')
    .updateCount();

// bad
const leds = stage.selectAll('.led').data(data).enter().append('svg:svg').classed('led', true)
    .attr('width', (radius + margin) * 2).append('svg:g')
    .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
    .call(tron.led);

// good
const leds = stage.selectAll('.led')
    .data(data)
  .enter().append('svg:svg')
    .classed('led', true)
    .attr('width', (radius + margin) * 2)
  .append('svg:g')
    .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
    .call(tron.led);

// good
const leds = stage.selectAll('.led').data(data);
// bad
function bar( foo ) {
  return foo;
}

// good
function bar(foo) {
  return foo;
}

// bad
if ( foo ) {
  console.log(foo);
}

// good
if (foo) {
  console.log(foo);
}
 
// bad
const foo = [ 1, 2, 3 ];
console.log(foo[ 0 ]);

// good
const foo = [1, 2, 3];
console.log(foo[0]);
// bad
const foo = {clark: 'kent'};

// good
const foo = { clark: 'kent' };
  • 避免一行代码超过100个字符,包括空格。eslint: max-len

    为何? 确保可读性和可维护性。

javascript // bad const foo = jsonData && jsonData.foo && jsonData.foo.bar && jsonData.foo.bar.baz && jsonData.foo.bar.baz.quux && jsonData.foo.bar.baz.quux.xyzzy; // bad $.ajax({ method: 'POST', url: 'https://airbnb.com/', data: { name: 'John' } }).done(() => console.log('Congratulations!')).fail(() => console.log('You have failed this city.')); // good const foo = jsonData && jsonData.foo && jsonData.foo.bar && jsonData.foo.bar.baz && jsonData.foo.bar.baz.quux && jsonData.foo.bar.baz.quux.xyzzy; // good $.ajax({ method: 'POST', url: 'https://airbnb.com/', data: { name: 'John' }, }) .done(() => console.log('Congratulations!')) .fail(() => console.log('You have failed this city.'));
⬆ 回到顶部

Airbnb React/JSX Style Guide

基本规范

  • 每一个文件只写一个模块.
  • 可是多个无状态模块能够放在单个文件中. eslint: react/no-multi-comp.
  • 推荐使用JSX语法.
  • 不要使用 React.createElement,除非从一个非JSX的文件中初始化你的app.

⬆ 回到顶部

建立模块

Class vs React.createClass vs stateless

// bad
const Listing = React.createClass({
    // ...
    render() {
        return <div>{this.state.hello}</div>;
    }
});
// good
class Listing extends React.Component {
// ...
    render() {
        return <div>{this.state.hello}</div>;
    }
}

若是你的模块没有状态或是没有引用refs, 推荐使用普通函数(非箭头函数)而不是类:

// bad
class Listing extends React.Component {
    render() {
        return <div>{this.props.hello}</div>;
    }
}
// bad (relying on function name inference is discouraged)
const Listing = ({ hello }) => (
    <div>{hello}</div>
);
// good
function Listing({ hello }) {
    return <div>{hello}</div>;
}

⬆ 回到顶部

命名

  • 扩展名: React模块使用 .jsx 扩展名.
  • 文件名: 文件名使用驼峰式. 如, ReservationCard.jsx.
  • 引用命名: React模块名使用驼峰式命名,实例使用骆驼式命名. eslint: react/jsx-pascal-case
// bad
import reservationCard from './ReservationCard';
// good
import ReservationCard from './ReservationCard';
// bad
const ReservationItem = <ReservationCard />;
// good
const reservationItem = <ReservationCard />;
  • 模块命名: 模块使用当前文件名同样的名称. 好比 ReservationCard.jsx 应该包含名为 ReservationCard的模块. 可是,若是整个文件夹是一个模块,使用 index.js做为入口文件,而后直接使用 index.js 或者文件夹名做为模块的名称:
// bad
import Footer from './Footer/Footer';
// bad
import Footer from './Footer/index';
// good
import Footer from './Footer';
  • 高阶模块命名: 对于生成一个新的模块,其中的模块名 displayName 应该为高阶模块名和传入模块名的组合. 例如, 高阶模块 withFoo(), 当传入一个 Bar 模块的时候, 生成的模块名 displayName 应该为 withFoo(Bar).

    为何?一个模块的 displayName 可能会在开发者工具或者错误信息中使用到,所以有一个能清楚的表达这层关系的值能帮助咱们更好的理解模块发生了什么,更好的Debug.

// bad
export default function withFoo(WrappedComponent) {
    return function WithFoo(props) {
        return <WrappedComponent {...props} foo />;
    }
}
// good
export default function withFoo(WrappedComponent) {
    function WithFoo(props) {
        return <WrappedComponent {...props} foo />;
    }
const wrappedComponentName = WrappedComponent.displayName
|| WrappedComponent.name
|| 'Component';
WithFoo.displayName = `withFoo(${wrappedComponentName})`;
    return WithFoo;
}
  • 属性命名: 避免使用DOM相关的属性来用做其余的用途。

    为何?对于styleclassName这样的属性名,咱们都会默认它们表明一些特殊的含义,如元素的样式,CSS class的名称。在你的应用中使用这些属性来表示其余的含义会使你的代码更难阅读,更难维护,而且可能会引发bug。

// bad
<MyComponent style="fancy" />
// good
<MyComponent variant="fancy" />

声明模块

  • 不要使用 displayName 来命名React模块,而是使用引用来命名模块, 如 class 名称.
// bad
export default React.createClass({
    displayName: 'ReservationCard',
    // stuff goes here
});
// good
export default class ReservationCard extends React.Component {
}

⬆ 回到顶部

代码对齐

// bad
<Foo superLongParam="bar"
anotherSuperLongParam="baz" />
// good, 有多行属性的话, 新建一行关闭标签
<Foo
    superLongParam="bar"
    anotherSuperLongParam="baz"
/>
// 若能在一行中显示, 直接写成一行
<Foo bar="bar" />
// 子元素按照常规方式缩进
<Foo
    superLongParam="bar"
    anotherSuperLongParam="baz"
>
    <Quux />
</Foo>

引号

  • 对于JSX属性值老是使用双引号("), 其余均使用单引号. eslint: jsx-quotes

    为何? JSX属性 不能包括转译的引号, 所以在双引号里包括像 "don't" 的属性值更容易输入.
    HTML属性也是用双引号,因此JSX属性也遵循一样的语法.

// bad
<Foo bar='bar' />
// good
<Foo bar="bar" />
// bad
<Foo style={{ left: "20px" }} />
// good
<Foo style={{ left: '20px' }} />

⬆ 回到顶部

空格

// bad
<Foo/>
// very bad
<Foo />
// bad
<Foo
/>
// good
<Foo />
// bad
<Foo bar={ baz } />
// good
<Foo bar={baz} />

⬆ 回到顶部

属性

  • JSX属性名使用骆驼式风格camelCase.
// bad
<Foo
    UserName="hello"
    phone_number={12345678}
/>
// good
<Foo
    userName="hello"
    phoneNumber={12345678}
/>
// bad
<Foo
    hidden={true}
/>
// good
<Foo
    hidden
/>
  • <img> 标签老是添加 alt 属性. 若是图片以presentation(感受是以相似PPT方式显示?)方式显示,alt 可为空, 或者<img> 要包含role="presentation". eslint: jsx-a11y/img-has-alt
// bad
<img src="hello.jpg" />
// good
<img src="hello.jpg" alt="Me waving hello" />
// good
<img src="hello.jpg" alt="" />
// good
<img src="hello.jpg" role="presentation" />
  • 不要在 alt 值里使用如 "image", "photo", or "picture"包括图片含义这样的词, 中文也同样. eslint: jsx-a11y/img-redundant-alt

    为何? 屏幕助读器已经把 img 标签标注为图片了, 因此没有必要再在 alt 里说明了.

// bad
<img src="hello.jpg" alt="Picture of me waving hello" />
// good
<img src="hello.jpg" alt="Me waving hello" />
// bad - not an ARIA role
<div role="datepicker" />
// bad - abstract ARIA role
<div role="range" />
// good
<div role="button" />
  • 不要在标签上使用 accessKey 属性. eslint: jsx-a11y/no-access-key

    为何? 屏幕助读器在键盘快捷键与键盘命令时形成的不统一性会致使阅读性更加复杂.

// bad
<div accessKey="h" />
// good
<div />
  • 避免使用数组的index来做为属性key的值,推荐使用惟一ID. (为何?)
// bad
{todos.map((todo, index) =>
    <Todo
        {...todo}
        key={index}
    />
)}
// good
{todos.map(todo => (
    <Todo
        {...todo}
        key={todo.id}
    />
))}

⬆ 回到顶部

refs

// bad
<Foo
    ref="myRef"
/>
// good
<Foo
    ref={ref => { this.myRef = ref; }}
/>

⬆ 回到顶部

括号

// bad
render() {
    return <MyComponent className="long body" foo="bar">
        <MyChild />
    </MyComponent>;
}
// good
render() {
    return (
        <MyComponent className="long body" foo="bar">
            <MyChild />
        </MyComponent>
    );
}
// good, 单行能够不须要
render() {
    const body = <div>hello</div>;
    return <MyComponent>{body}</MyComponent>;
}

⬆ 回到顶部

标签

// bad
<Foo className="stuff"></Foo>
// good
<Foo className="stuff" />
// bad
<Foo
bar="bar"
baz="baz" />
// good
<Foo
bar="bar"
baz="baz"
/>

⬆ 回到顶部

函数

  • 使用箭头函数来获取本地变量.
function ItemList(props) {
    return (
        <ul>
            {props.items.map((item, index) => (
                <Item
                    key={item.key}
                    onClick={() => doSomethingWith(item.name, index)}
                />
            ))}
        </ul>
    );
}
  • 当在 render() 里使用事件处理方法时,提早在构造函数里把 this 绑定上去. eslint: react/jsx-no-bind

    为何? 在每次 render 过程当中, 再调用 bind 都会新建一个新的函数,浪费资源.

// bad
class extends React.Component {
    onClickDiv() {
        // do stuff
    }
    render() {
        return <div onClick={this.onClickDiv.bind(this)} />
    }
}
// good
class extends React.Component {
    constructor(props) {
        super(props);
        this.onClickDiv = this.onClickDiv.bind(this);
    }
    onClickDiv() {
        // do stuff
    }
    render() {
        return <div onClick={this.onClickDiv} />
    }
}
  • 在React模块中,不要给所谓的私有函数添加 _ 前缀,本质上它并非私有的.

    为何?_ 下划线前缀在某些语言中一般被用来表示私有变量或者函数。可是不像其余的一些语言,在JS中没有原生支持所谓的私有变量,全部的变量函数都是共有的。尽管你的意图是使它私有化,在以前加上下划线并不会使这些变量私有化,而且全部的属性(包括有下划线前缀及没有前缀的)都应该被视为是共有的。了解更多详情请查看Issue #1024, 和 #490

// bad
React.createClass({
    _onClickSubmit() {
        // do stuff
    },
    // other stuff
});
// good
class extends React.Component {
    onClickSubmit() {
        // do stuff
    }
    // other stuff
}
// bad
render() {
    (<div />);
}
// good
render() {
    return (<div />);
}

⬆ 回到顶部

模块生命周期

  • class extends React.Component 的生命周期函数:
  1. 可选的 static 方法
  2. constructor 构造函数
  3. getChildContext 获取子元素内容
  4. componentWillMount 模块渲染前
  5. componentDidMount 模块渲染后
  6. componentWillReceiveProps 模块将接受新的数据
  7. shouldComponentUpdate 判断模块需不须要从新渲染
  8. componentWillUpdate 上面的方法返回 true, 模块将从新渲染
  9. componentDidUpdate 模块渲染结束
  10. componentWillUnmount 模块将从DOM中清除, 作一些清理任务
  11. 点击回调或者事件处理器onClickSubmit()onChangeDescription()
  12. render 里的 getter 方法getSelectReason()getFooterContent()
  13. 可选的 render 方法renderNavigation()renderProfilePicture()
  14. render render() 方法
  • 如何定义 propTypes, defaultProps, contextTypes, 等等其余属性...
import React, { PropTypes } from 'react';
const propTypes = {
    id: PropTypes.number.isRequired,
    url: PropTypes.string.isRequired,
    text: PropTypes.string,
};
const defaultProps = {
    text: 'Hello World',
};
class Link extends React.Component {
    static methodsAreOk() {
        return true;
    }
    render() {
        return <a href={this.props.url} data-id={this.props.id}>{this.props.text}</a>
    }
}
Link.propTypes = propTypes;
Link.defaultProps = defaultProps;
export default Link;
  • React.createClass 的生命周期函数,与使用class稍有不一样: eslint: react/sort-comp
  1. displayName 设定模块名称
  2. propTypes 设置属性的类型
  3. contextTypes 设置上下文类型
  4. childContextTypes 设置子元素上下文类型
  5. mixins 添加一些mixins
  6. statics
  7. defaultProps 设置默认的属性值
  8. getDefaultProps 获取默认属性值
  9. getInitialState 或者初始状态
  10. getChildContext
  11. componentWillMount
  12. componentDidMount
  13. componentWillReceiveProps
  14. shouldComponentUpdate
  15. componentWillUpdate
  16. componentDidUpdate
  17. componentWillUnmount
  18. clickHandlers or eventHandlers like onClickSubmit() or onChangeDescription()
  19. getter methods for render like getSelectReason() or getFooterContent()
  20. Optional render methods like renderNavigation() or renderProfilePicture()
  21. render

⬆ 回到顶部

ismounted

  • 不要再使用 isMounted. eslint: react/no-is-mounted

    为何? [isMounted 反人类设计模式:()][anti-pattern], 在 ES6 classes 中没法使用, 官方将在将来的版本里删除此方法.
    [anti-pattern]: https://facebook.github.io/react/blog/2015/12/16/ismounted-antipattern.html

⬆ 回到顶部

Enjoy Yourself~

Any feedback or complain or requests of you, please send email to Feedback

相关文章
相关标签/搜索