[原文链接]http://feclub.cn/post/content/eslint

1. ESLint 规范选讲

1.1 References

1.1.1 优先使用 const 来声明变量; 避免使用 var.

  • eslint: prefer-const, no-const-assign

1.1.2 如果申明的变量必须要改变, 使用 let.

  • eslint: no-var

针对不需要改变的变量,优先使用 const,这样可以保证不会在其它地方意外地改变这个值或者引用。

// bad
var a = 1
var b = {}

// 👍
const a = 1
const b = {}
// bad
var count = 1
if (true) {
  count += 1
}

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

1.2 Objects

1.2.1 Use property value shorthand.

  • eslint: object-shorthand
const lukeSkywalker = 'Luke Skywalker'

// bad
const obj = {
  lukeSkywalker: lukeSkywalker
}

// good
const obj = {
  lukeSkywalker
}

1.2.2 浅拷贝时使用拓展运算符,而不是 Object.assign

// 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 }

拓展运算符在类数组转换和数组去重中的运用

1.3 Arrays

1.3.1 使用拓展运算符复制数组。

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

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

// good
const itemsCopy = [...items]
[...new Set(arr)]

1.3.2 使用...代替 Array.from 来进行类数组至数组的转换。

const foo = document.querySelectorAll('.foo')

arguments
// good
const nodes = Array.from(foo)

// best
const nodes = [...foo]

1.4 Destructuring

1.4.1 对象的解构赋值

  • eslint: prefer-destructuring
// bad
function getFullName(user) {
  const firstName = user.firstName
  const lastName = user.lastName

  return `${firstName} ${lastName}`
}

// good
function getFullName(user) {
  const { firstName, lastName } = user
  return `${firstName} ${lastName}`
}

// best
function getFullName({ firstName, lastName }) {
  return `${firstName} ${lastName}`
}

1.4.2 数组的解构赋值

  • eslint: prefer-destructuring
const arr = [1, 2, 3, 4]

// bad
const first = arr[0]
const second = arr[1]

// good
const [first, second, ...rest] = arr



1.4.3 优先使用模版字符串

// bad
function sayHi(name) {
  return 'How are you, ' + name + '?'
}

// bad
function sayHi(name) {
  return ['How are you, ', name, '?'].join()
}

// bad
function sayHi(name) {
  return `How are you, ${name}?`
}

// good
function sayHi(name) {
  return `How are you, ${name}?`
}

1.5 Functions

1.5.1 合理使用函数参数默认值

// really bad
function handleThings(opts) {
  opts = opts || {}
  // ...
}

// still bad
function handleThings(opts) {
  if (opts === void 0) {
    opts = {}
  }
  // ...
}

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

1.5.2 不要直接改变函数参数. eslint: no-param-reassign

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

// good
function f2(obj) {
  const key = Object.prototype.hasOwnProperty.call(obj, 'key') ? obj.key : 1
}
// 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) {
  // ...
}

1.5 Classes

1.5.1 使用 Class 和 extends

  • 简洁易于理解,语义性强
// 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]
  }
  static pop() {
    const value = this.queue[0]
    this.queue.splice(0, 1)
    return value
  }
}
// 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]
  }
}

1.6.2 使用方法执行链

// 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)

1.final

  • 合理使用编辑器的 eslint fix 功能
  • 格式化不要使用自己的个性化配置,按照项目内的 eslint 配置  进行格式化

2. 代码重构

2.1 提炼函数

  • 避免超大函数
  • 利于代码复用
  • 利于单元测试
const getInfo = function(params) {
  ajax('http://baidu.com/api', data => {
    global.name = data.name
    global.age = data.age
    global.sex = data.sex
  })
}

// 抽离
const getInfo = function(params) {
  ajax('http://baidu.com/api', data => {
    setInfo(data)
  })
}

const setInfo = function(data) {
  global.name = data.name
  global.age = data.age
  global.sex = data.sex
}

2.2 合并重复条件

  • 例如函数体内有一些分支条件,每个分支条件内散步了一些重复的代码
const paging = function(curPage) {
  if (curPage <= 0) {
    curPage = 0
  } else if (curPage >= totalPage) {
    curPage = totalPage
  }
  jump(curPage)
}

2.3 条件抽离

  • 复杂的判断条件应该抽离成单独的函数
const getPrice = function(goods) {
  if (goods.price > 10000 && goods.price < 20000 && goods.isCheap) {
    return goods.price * 0.8
  }
  return goods.price
}
const isNeedDiscount = function(goods) {
  return goods.price > 10000 && goods.price < 20000 && goods.isCheap
}

const getPrice = function(goods) {
  if (isNeedDiscount(goods)) {
    return goods.price * 0.8
  }
  return goods.price
}

2.4 熟悉并运用各种数组和对象的方法

避免:

  • 遍历数组只会 forEach 或者 for(){}
  • 给数组添加元素只会用 push。
    push()
    push()
    应该:

  • 考虑 every、some、filter、map、reduce 等等

  • 考虑 concat、unshift、splice 等等

2.5 事不过三原则

  • 重复或者类似的条件和功能出现达到三次,这段代码就是很垃圾的代码。
  • 经常出现在诸如判断接口 code,判断用户各种状态的场景中
const cal = function(lev, money) {
  if (lev === 'A') {
    return money * 10
  }
  if (lev === 'B') {
    return money * 8
  }
  if (lev === 'C') {
    return money * 6
  }
  if (lev === 'D') {
    return money * 0
  }
}
const calFuncMap = {
  A: money => money * 10,
  B: money => money * 8,
  C: money => money * 6,
  D: money => money * 0
}

calFuncMap['A'](5000)
const calMap = {
  A: 10,
  B: 8,
  C: 6,
  D: 0
}

const cal = function(lev, money) {
  return money * calMap[lev]
}

2.5 提前退出,代替 if 嵌套

if (a) {
  foo()
  if (b) {
    bar()
    if (c) {
      boo()
    }
  }
}
// good
if (!a) return
foo()
if (!b) return
bar()
if (!c) return
boo()

2.6 主动应用上述 ESLint 建议的内容

  • 链式调用
  • 解构复制
  • 默认参数
  • Class
  • ...

2.7 态度端正,对自己写的代码负责