Skip to content

目录

以下规则说明均来自 airbnb

变量声明

prefer-const; no-const-assign

  • 所有的赋值都用 const,避免使用 var。eslint: prefer-const, no-const-assign

    为什么?因为这个能确保你不会改变你的初始值,重复引用会导致 bug 并且使代码变得难以理解。

    javascript
    // bad
    var a = 1;
    var b = 2;
    
    // good
    const a = 1;
    const b = 2;

no-var

  • 如果你一定要对参数重新赋值,使用 let,而不是 var。eslint: no-var

为什么?因为 let 是块级作用域,而 var 是函数级作用域。

javascript
// bad
var count = 1;
if (true) {
  count += 1;
}

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

no-use-before-define

变量、类、函数都应该在使用前定义。 eslint: no-use-before-define

为什么? 当变量、类或者函数在使用处之后定义,这让阅读者很难想到这个函数引用自何处。 对于读者在遇到某个事物之前,如果能知道这个事物的来源(不论是在文件中定义还是从别的模块引用),理解起来都会清晰很多。

javascript
// 不好的

// 变量 a 使用出现在定义之前
console.log(a); // 这样会导致 undefined,虽然变量声明被提升了, 但 a 初始化复制却还没执行
var a = 10;

// 函数 fun 使用出现在定义之前
fun();
function fun() {}

// 类 A 使用出现在定义之前
new A(); // 引用错误: 无法在 A 初始化之前访问它
class A {}

// `let` 和 `const` 被提升, 但是他们没有初始化变量值
// 变量 a、 b 都被放在了 JavaScript 的暂时性死区 (Temporal Dead Zone, 指在变量被声明之前无法访问它的现象)。

console.log(a); // 引用错误: 无法在 a 初始化之前访问它
console.log(b); // 引用错误: 无法在 b 初始化之前访问它
let a = 10;
const b = 5;

// 好的

var a = 10;
console.log(a); // 10

function fun() {}
fun();

class A {}
new A();

let a = 10;
const b = 5;
console.log(a); // 10
console.log(b); // 5

⬆ 返回顶部

对象

no-new-object

  • 使用字面值创建对象。eslint: no-new-object

    javascript
    // bad
    const item = new Object();
    
    // good
    const item = {};

object-shorthand

用对象方法简写。eslint: object-shorthand

javascript
// bad
const atom = {
  value: 1,

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

// good
const atom = {
  value: 1,

  // 对象的方法
  addValue(value) {
    return atom.value + value;
  },
};

object-shorthand

用属性值缩写。eslint: object-shorthand

为什么?这样写更简洁,且可读性更高。

javascript
const lukeSkywalker = "Luke Skywalker";

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

// good
const obj = {
  lukeSkywalker,
};

prefer-object-spread

对象浅拷贝时,更推荐使用扩展运算符(即 ... 运算符),而不是 Object.assign。获取对象指定的几个属性时,用对象的 rest 解构运算符(即 ... 运算符)更好。eslint: prefer-object-spread

  • 这一段不太好翻译出来, 大家看下面的例子就懂了。^.^
javascript
// very bad
const original = { a: 1, b: 2 };
const copy = Object.assign(original, { c: 3 }); // 改了 `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 es6 扩展运算符 ...
const original = { a: 1, b: 2 };
// 浅拷贝
const copy = { ...original, c: 3 }; // copy => { a: 1, b: 2, c: 3 }

// rest 解构运算符
const { a, ...noA } = copy; // noA => { b: 2, c: 3 }

⬆ 返回顶部

数组

no-array-constructor

用字面量创建数组。eslint: no-array-constructor

javascript
// bad
const items = new Array();

// good
const items = [];

arrays-callback-return

在数组方法的回调函数中使用 return 语句。如果函数体由一条返回一个表达式的语句组成,并且这个表达式没有副作用, 这个时候可以忽略 return。eslint: array-callback-return

javascript
// good
[1, 2, 3].map((x) => {
  const y = x + 1;
  return x * y;
});

// good 函数只有一个语句
[1, 2, 3].map((x) => x + 1);

// bad - 没有返回值, 因为在第一次迭代后 acc 就变成 undefined 了
[
  [0, 1],
  [2, 3],
  [4, 5],
].reduce((acc, item, index) => {
  const flatten = acc.concat(item);
});

// good
[
  [0, 1],
  [2, 3],
  [4, 5],
].reduce((acc, item, index) => {
  const flatten = acc.concat(item);
  return flatten;
});

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

⬆ 返回顶部

解构

prefer-destructuring

用对象的解构赋值来获取和使用对象某个或多个属性值。eslint: prefer-destructuring

为什么? 解构使您不必为这些属性创建临时引用,并且避免重复引用对象。重复引用对象将造成代码重复、增加阅读次数、提高犯错概率。在一个块级作用域里,解构对象可以在同一个地方给解构字段赋值,而不需要读整个的代码块看它到底用了哪些字段。

javascript
// 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}`;
}

用数组解构。eslint: prefer-destructuring

javascript
const arr = [1, 2, 3, 4];

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

// good
const [first, second] = arr;

⬆ 返回顶部

字符串

prefer-template

当需要动态生成字符串时,使用模板字符串而不是字符串拼接。eslint: prefer-template template-curly-spacing

为什么?模板字符串更具可读性、多行语法更简洁以及更方便插入变量到字符串里头。

javascript
// 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}?`;
}

no-eval

永远不要使用 eval(),该方法有太多漏洞。eslint: no-eval

⬆ 返回顶部

函数

wrap-iife

把立即执行函数包裹在圆括号里。eslint: wrap-iife

立即执行函数:Immediately Invoked Function expression = IIFE。 为什么?一个立即调用的函数表达式是一个单元 - 把它和它的调用者(圆括号)包裹起来,使代码读起来更清晰。 另外,在模块化世界里,你几乎用不着 IIFE。

javascript
// immediately-invoked function expression (IIFE)
(function () {
  console.log("Welcome to the Internet. Please follow me.");
})();

no-loop-func

不要在非函数块(ifwhile 等)内声明函数。把这个函数分配给一个变量。浏览器会允许你这样做,但不同浏览器的解析方式不同,这是一个坏消息。eslint: no-loop-func

prefer-rest-params

不要使用 arguments,用收集参数语法 ... 代替。eslint: prefer-rest-params

为什么?... 明确你想用哪个参数。而且收集参数是真数组,而不是类似数组的 arguments

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

// good
function concatenateAll(...args) {
  return args.join("");
}

default-param-last

把默认参数赋值放在最后。eslint: default-param-last

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

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

no-new-func

不要用函数构造器创建函数。eslint: no-new-func

为什么?以这种方式创建函数将类似于字符串 eval(),存在漏洞。

javascript
// bad
const add = new Function("a", "b", "return a + b");

// still bad
const subtract = Function("a", "b", "return a - b");

no-param-reassign

不要修改参数. eslint: no-param-reassign

为什么?操作参数对象对原始调用者会导致意想不到的副作用。就是不要改参数的数据结构,保留参数原始值和数据结构。

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

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

⬆ 返回顶部

箭头函数

arrow-parens

如果函数体由一个没有副作用的 表达式 语句组成,删除大括号和 return。否则,使用大括号和 return 语句。 eslint: arrow-parens, arrow-body-style

为什么?语法糖,当多个函数链在一起的时候好读。

javascript
// bad map 没有 return
[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 + 1}.`);

// 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,
}));

// 没有明显的存在副作用的 return 语句
function foo(callback) {
  const val = callback();
  if (val === true) {
    // 当 callback 返回 true 时在这里执行
  }
}

let bool = false;

// bad
foo(() => (bool = true));

// good
foo(() => {
  bool = true;
});

⬆ 返回顶部

模块

no-duplicate-imports

一个路径只 import 一次。eslint: no-duplicate-imports

为什么?多行导入同一路径将使代码变得难以维护。

javascript
// bad
import foo from "foo";
// … 其他导入 … //
import { named1, named2 } from "foo";

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

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

import/no-mutable-exports

不要导出可变的东西。eslint: import/no-mutable-exports

为什么?变化通常都是需要避免,特别是当你要输出可变的绑定。虽然在某些场景下可能需要这种技术,但总的来说应该导出常量。

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

// good
const foo = 3;
export { foo };

import/prefer-default-export

在一个单一导出模块里,用 export default 更好。eslint: import/prefer-default-export

为什么?鼓励使用更多文件,每个文件只导出一次,这样可读性和可维护性更好。

javascript
// bad
export function foo() {}

// good
export default function foo() {}

import/first

import 放在其他所有语句之前。eslint: import/first

为什么?因为 import 会被提升到代码最前面运行,因此将他们放在最前面以防止发生意外行为。

javascript
// bad
import foo from "foo";
foo.init();

import bar from "bar";

// good
import foo from "foo";
import bar from "bar";

foo.init();

⬆ 返回顶部

属性

dot-notation

访问属性时使用点符号。eslint: dot-notation

javascript
const luke = {
  jedi: true,
  age: 28,
};

// bad
const isJedi = luke["jedi"];

// good
const isJedi = luke.jedi;

⬆ 返回顶部

其他

no-unneeded-ternary

避免不必要的三元表达式。eslint rules: no-unneeded-ternary

javascript
// bad
const foo = a ? a : b;
const bar = c ? true : false;
const baz = c ? false : true;
const quux = a != null ? a : b;

// good
const foo = a || b;
const bar = !!c;
const baz = !c;
const quux = a ?? b;

brace-style

if 表达式的 elseif 的右大括号在一行。eslint: brace-style

javascript
// bad
if (test) {
  thing1();
  thing2();
} else {
  thing3();
}

// good
if (test) {
  thing1();
  thing2();
} else {
  thing3();
}

no-multiple-empty-lines

不要在代码之间使用多个空白行填充。eslint: no-multiple-empty-lines

javascript
// bad
class Person {
  constructor(fullName, email, birthday) {
    this.fullName = fullName;

    this.email = email;

    this.setAge(birthday);
  }

  setAge(birthday) {
    const today = new Date();

    const age = this.getAge(today, birthday);

    this.age = age;
  }

  getAge(today, birthday) {
    // ..
  }
}

// good
class Person {
  constructor(fullName, email, birthday) {
    this.fullName = fullName;
    this.email = email;
    this.setAge(birthday);
  }

  setAge(birthday) {
    const today = new Date();
    const age = getAge(today, birthday);
    this.age = age;
  }

  getAge(today, birthday) {
    // ..
  }
}

max-len

避免一行代码超过 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;

// better
const foo = 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."));

⬆ 返回顶部

命名规范

id-length

避免用一个字母命名,让你的命名有意义。eslint: id-length

javascript
// bad
function q() {
  // ...
}

// good
function query() {
  // ...
}

camelcase

用小驼峰命名法来命名你的对象、函数、实例。eslint: camelcase

javascript
// bad
const OBJEcttsssss = {};
const this_is_my_object = {};
function c() {}

// good
const thisIsMyObject = {};
function thisIsMyFunction() {}