Airbnb规范

2017-12-10  本文已影响0人  NukeLuke

为什么? 当 JavaScript 遇到没有分号的换行符时,它使用一组称为自动分号插入的规则来确定是否应该将换行符视为语句的结尾,并且(顾名思义)如果被这样认为的话,在换行符前面自动插入一个分号。ASI(自动分号插入)包含了一些稀奇古怪的的行为,不过,如果 JavaScript 错误地解释了你的换行符,你的代码将会被中断执行。随着新功能成为 JavaScript 的一部分,这些规则将变得更加复杂。明确地结束你的语句并配置你的 linter 来捕获缺少的分号,将有助于防止遇到问题

const a = [1, 2], const b = a, b[0] = 9, a = ?, b = ?
// bad
const obj = new Object(), const arr = new Array()

// good
const obj = {1, 2, 3}, const arr = [7, 8, 9]
 { 1, 2, 3 }
[1, 2, 3]
// 注释
const a = [1, 2, 3]
const obj = { abc: 123 }
// bad
const atom = {
    value: 1,
 
    addValue: function (value) {
    return atom.value + value;
    },
}

// good
const atom = {
    value: 1,
 
    addValue(value) {
    return atom.value + value;
    },
}
// 为什么? 函数声明很容易被提升(Hoisting),你可以在函数被定义之前引用该函数。这对可读性和可维护性来说都是不利的。

// bad
function fn () {}

// good
const fn = () => {}
// bad
const obj = { abc: abc }

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

// good
const good = {
    foo: 3,
    bar: 4,
    'data-blah': 5,
}
// bad
const len = items.length
const itemsCopy = []
let i
 
for (i = 0; i < len; i += 1) {
    itemsCopy[i] = items[i]
}
 
// good
const itemsCopy = [...items]
const foo = document.querySelectorAll('.foo');
 
// good
const nodes = Array.from(foo);
 
// best
const nodes = [...foo];
// bad
inbox.filter((msg) => {
    const { subject, author } = msg;
    if (subject === 'Mockingbird') {
    return author === 'Harper Lee'
    } else {
    return false
    }
})
 
// good
inbox.filter((msg) => {
    const { subject, author } = msg;
    if (subject === 'Mockingbird') {
    return author === 'Harper Lee'
    }
 
    return false
})
// 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}`
}
const arr = [1, 2, 3, 4]
 
// bad
const first = arr[0]
const second = arr[1]
 
// good
const [first, second] = arr
// bad
const name = "Capt. Janeway"
 
// bad - 模板字面量应该包含插值或换行符
const name = `Capt. Janeway`
 
// good
const name = 'Capt. Janeway'
// 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}?`
}
//为什么?使用 ... 能明确你要传入的参数。另外 rest(剩余)参数是一个真正的数组,而 arguments 是一个类数组(Array-like)。

// bad
function concatenateAll() {
    const args = Array.prototype.slice.call(arguments);
    return args.join('');
}
 
// good
function concatenateAll(...args) {
    return args.join('');
}
// bad
function handleThings(opts) {
    opts = opts || {};
      // 如果opts的值就是false怎么办?按上面的写法,它永远等于{}了,也就是true
    // ...
}
 
// good
function handleThings(opts = {}) {
    // ...
}
// 为什么?因为对象是引用类型,操作作为参数传入的对象,可能会在调用原始对象时造成不必要的变量副作用。

// 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) {
    // ...
}
// bad
[1, 2, 3].map((x) => x * x)
 
// good
[1, 2, 3].map(x => x * x)
 
// good
[1, 2, 3].map(number => (
    `A long string with the ${number}. It’s so long that we don’t want it to take up space on the .map line!`
))
 
// bad
[1, 2, 3].map(x => {
    const y = x + 1
    return x * y
})
 
// good
[1, 2, 3].map((x) => {
    const y = x + 1
    return x * y
})
// bad
import foo from 'foo'
// … 其他一些 imports … //
import { named1, named2 } from 'foo'
 
// good
import foo, { named1, named2 } from 'foo'
 
// good
import foo, {
    named1,
    named2,
} from 'foo'
// bad
import foo from 'foo'
foo.init()
 
import bar from 'bar'
 
// good
import foo from 'foo'
import bar from 'bar'
 
foo.init()
// 为什么? 这是强制执行我们不变性的规则。 处理返回值的纯函数比副作用更容易推理。

// 使用 map() / every() / filter() / find() / findIndex() / reduce() / some() / … 来迭代数组, 使用 Object.keys() / Object.values() / Object.entries() 来生成数组,以便可以迭代对象。

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
const sum = numbers.reduce((total, num) => total + num, 0);
sum === 15
 
// bad
const increasedByOne = [];
for (let i = 0; i < numbers.length; i++) { increasedByOne.push(numbers[i] + 1); } // good const increasedByOne = []; numbers.forEach((num) => {
    increasedByOne.push(num + 1)
})
 
// best
const increasedByOne = numbers.map(num => num + 1)
const items = getItems()
const goSportsTeam = true
const dragonball = 'z'
let a = 1

// bad
a++

// good
a += 1
// bad
switch (foo) {
    case 1:
    let x = 1;
    break
    case 2:
    const y = 2;
    break
    case 3:
    function f() {
        // ...
    }
    break
    default:
    class C {}
}
 
// good
switch (foo) {
    case 1: {
    let x = 1;
    break
    }
    case 2: {
    const y = 2;
    break
    }
    case 3: {
    function f() {
        // ...
    }
    break
    }
    case 4:
    bar()
    break
    default: {
    class C {}
    }
}
// bad
const foo = maybe1 > maybe2
    ? "bar"
    : value1 > value2 ? "baz" : null
 
// 拆分成2个分离的三元表达式
const maybeNull = value1 > value2 ? 'baz' : null
 
// better
const foo = maybe1 > maybe2
    ? 'bar'
    : maybeNull
 
// best
const foo = maybe1 > maybe2 ? 'bar' : maybeNull
// bad
const foo = a ? a : b
const bar = c ? true : false
const baz = c ? false : true
 
// good
const foo = a || b
const bar = !!c
const baz = !c
// bad
const foo = a && b < 0 || c > 0 || d + 1 === 0
 
// bad
const bar = a ** b - 5 % d
 
// bad
if (a || b && c) {
    return d
}
 
// good
const foo = (a && b < 0) || c > 0 || (d + 1 === 0)
 
// good
const bar = (a ** b) - (5 % d)
 
// good
if ((a || b) && c) {
    return d
}
 
// good
const bar = a + b / c * d
// bad
function foo() {
    if (x) {
    return x
    } else {
    return y
    }
}
 
// bad
function cats() {
    if (x) {
    return x
    } else if (y) {
    return y
    }
}
 
// bad
function dogs() {
    if (x) {
    return x
    } else {
    if (y) {
        return y
    }
    }
}
 
// good
function foo() {
    if (x) {
    return x
    }
 
    return y
}
 
// good
function cats() {
    if (x) {
    return x
    }
 
    if (y) {
    return y
    }
}
 
//good
function dogs(x) {
    if (x) {
    if (z) {
        return y
    }
    } else {
    return z
    }
}
// bad
function test(){
    console.log('test')
}
 
// good
function test() {
    console.log('test')
}
 
// bad
dog.set('attr',{
    age: '1 year',
    breed: 'Bernese Mountain Dog',
})
 
// good
dog.set('attr', {
    age: '1 year',
    breed: 'Bernese Mountain Dog',
})
// bad
if(isJedi) {
    fight ()
}
 
// good
if (isJedi) {
    fight()
}
 
// bad
function fight () {
    console.log ('Swooosh!')
}
 
// good
function fight() {
    console.log('Swooosh!')
}
// bad
const x=y+5
 
// good
const x = y + 5
// => this.reviewScore = 9
 
// bad
const totalScore = new String(this.reviewScore) // typeof totalScore 是 "object" 而不是 "string"
 
// bad
const totalScore = this.reviewScore + '' // 调用 this.reviewScore.valueOf()
 
// bad
const totalScore = this.reviewScore.toString() // 不能保证返回一个字符串
 
// good
const totalScore = String(this.reviewScore)
const inputValue = '4'
 
// bad
const val = new Number(inputValue)
 
// bad
const val = +inputValue
 
// bad
const val = inputValue >> 0
 
// bad
const val = parseInt(inputValue)
 
// good
const val = Number(inputValue)
 
// good
const val = parseInt(inputValue, 10)
const age = 0
 
// bad
const hasAge = new Boolean(age)
 
// good
const hasAge = Boolean(age)
 
// best
const hasAge = !!age
// bad
$(this).trigger('listingUpdated', listing.id)
 
// ...
 
$(this).on('listingUpdated', (e, listingId) => {
    // do something with listingId
})

// good
$(this).trigger('listingUpdated', { listingId: listing.id })
 
// ...
 
$(this).on('listingUpdated', (e, data) => {
    // do something with data.listingId
})
// 为什么?全局的 isNaN 方法会将非数字转换为数字, 任何被转换为 NaN 的东西都会返回 true

// bad
isNaN('1.2') // false
isNaN('1.2.3') // true
 
// good
Number.isNaN('1.2.3') // false
Number.isNaN(Number('1.2.3')) // true
// 为什么?全局的 isFinite 方法会将非数字转换为数字, 任何被转换为有限大的数字都会返回 true 


// bad
isFinite('2e3') // true
 
// good
Number.isFinite('2e3') // false
Number.isFinite(parseInt('2e3', 10)) // true
上一篇 下一篇

猜你喜欢

热点阅读