JavaScript 风格指南 精选版

本风格主要精选自 airbnbstandard 实战中高频和容易理解的规范

Semi 分号

  • 不要使用分号。 eslint: semi
js 复制代码
// bad
window.alert('hi');  
// good 
window.alert('hi')

References 引用

对您的所有引用使用 const;避免使用 var。eslint:prefer-const

js 复制代码
// bad
var a = 1;
var b = 2;

// good
const a = 1;
const b = 2;

避免修改使用 const 声明的变量 。 eslint: no-const-assign

js 复制代码
// bad
const score = 100
score = 125

如果必须重新分配引用,请使用 let 而不是 var。ESLint: no-var

js 复制代码
// bad
var count = 1;
if (true) {
  count += 1;
}

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

Objects 对象

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

js 复制代码
// bad
const item = new Object();

// good
const item = {};

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

js 复制代码
// 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

js 复制代码
const name = 'jason';

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

// good
const obj = {
  name,
};

在对象声明的开头对简写的属性进行分组。

js 复制代码
const name = 'jason';
const age = 18;

// bad
const obj = { 
  email: 'jason@gmail.com',
  name,
  age,
};

// good
const obj = {
  name,
  age,
  email: 'jason@gmail.com',
};

字面量对象的key不使用字符串。eslint: quote-props

js 复制代码
// bad
const bad = {
  'foo': 3,
  'bar': 4,
  'data-blah': 5,
};

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

使用解构{...}来进行浅拷贝,代替Object.assign eslint: prefer-object-spread

js 复制代码
// 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 }

Arrays 数组

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

js 复制代码
// bad
const items = new Array();

// good
const items = [];

使用 Array的push 代替直接赋值obj[0]= 'a' 赋值

js 复制代码
const someStack = [];

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

// good
someStack.push('abracadabra');

使用数组展开 ... 复制数组。

js 复制代码
// bad
const len = items.length;
const itemsCopy = [];
let i;

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

// good
const itemsCopy = [...items];

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

js 复制代码
// good
[1, 2, 3].map((x) => {
  const y = x + 1;
  return x * y;
});

// good
[1, 2, 3].map((x) => x + 1);

// bad - no returned value means `acc` becomes undefined after the first iteration
[[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;
});

数组少的一行显示,多行则在换行显示

js 复制代码
// bad
const arr = [
  [0, 1], [2, 3], [4, 5],
];

const objectInArray = [{
  id: 1,
}, {
  id: 2,
}];

const numberInArray = [
  1, 2,
];

// good
const arr = [[0, 1], [2, 3], [4, 5]];

const objectInArray = [
  {
    id: 1,
  },
  {
    id: 2,
  },
];

const numberInArray = [
  1,
  2,
];

Destructuring 解构

对象的属性使用解构访问。eslint: prefer-destructuring

js 复制代码
// 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

js 复制代码
const arr = [1, 2, 3, 4];

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

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

Strings 字符串

对字符串使用单引号 ''。eslint: quotes

js 复制代码
// bad
const name = "Capt. Janeway";

// bad - template literals should contain interpolation or newlines
const name = `Capt. Janeway`;

// good
const name = 'Capt. Janeway';

行超过 100 个字符 依然一行显示,不应该换行或多行拼接显示。 eslint: no-multi-str

js 复制代码
// bad
const errorMessage = 'This is a super long error that was thrown because \
of Batman. When you stop to think about how Batman had anything to do \
with this, you would get nowhere \
fast.';

// bad
const errorMessage = 'This is a super long error that was thrown because ' +
  'of Batman. When you stop to think about how Batman had anything to do ' +
  'with this, you would get nowhere fast.';

// good
const errorMessage = 'This is a super long error that was thrown because of Batman. When you stop to think about how Batman had anything to do with this, you would get nowhere fast.';

使用模板字符串构建字符串,而不是+拼接。eslint: prefer-template

js 复制代码
// 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}?`;
}

模板字符串中变量前后不加空格 。 eslint: template-curly-spacing

js 复制代码
const message = `Hello, ${ name }`    // ✗ avoid
const message = `Hello, ${name}`      // ✓ ok

Functions 函数

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

js 复制代码
// bad
function foo() {
  // ...
}

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

// good
// lexical name distinguished from the variable-referenced invocation(s)
const short = function longUniqueMoreDescriptiveLexicalFoo() {
  // ...
};

禁止使用 Function 构造器 。 eslint: no-new-func

js 复制代码
var sum = new Function('a', 'b', 'return a + b')    // ✗ avoid

将立即调用的函数表达式包裹在括号中。eslint:wrap-iife

js 复制代码
// immediately-invoked function expression (IIFE)
(function () {
  console.log('Welcome to the Internet. Please follow me.');
}());

使用 rest 语法 ...args 代替 arguments eslint: prefer-rest-params

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

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

使用默认参数语法而不是更改函数参数。eslint: no-param-reassign

js 复制代码
// really bad
function handleThings(opts) {
  opts = opts || {};
}

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

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

始终将默认参数放在最后。eslint: default-param-last

js 复制代码
// bad
function handleThings(opts = {}, name) {
  // ...
}

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

函数定义中的间距。eslint: space-before-function-paren

js 复制代码
// bad
const f = function(){};
const g = function (){};
const h = function() {};

// good
const x = function () {};
const y = function a() {};

代码块首尾留空格 。 eslint: space-before-blocks

js 复制代码
if (admin){...}     // ✗ avoid
if (admin) {...}    // ✓ ok

使用... spread语法来调用可变参数函数。eslint: prefer-spread

js 复制代码
// bad
const x = [1, 2, 3, 4, 5];
console.log.apply(console, x);

// good
const x = [1, 2, 3, 4, 5];
console.log(...x);

// bad
new (Function.prototype.bind.apply(Date, [null, 2016, 8, 5]));

// good
new Date(...[2016, 8, 5]);

函数多个参数调用,多个参数换行,都后接逗号。eslint: function-paren-newline

js 复制代码
// bad
function foo(bar,
              baz,
              quux) {
  // ...
}

// good
function foo(
  bar,
  baz,
  quux,
) {
  // ...
}

// bad
console.log(foo,
  bar,
  baz);

// good
console.log(
  foo,
  bar,
  baz,
);

点号操作符须与属性需在同一行 。 eslint: dot-location

js 复制代码
// bad
  console.
    log('hello') 
// good
  console
    .log('hello')

函数调用时标识符与括号间不留间隔 。 eslint: func-call-spacing

js 复制代码
// bad
console.log ('hello') 
// good
console.log('hello')

嵌套的代码块中禁止再定义函数 。 eslint: no-inner-declarations

js 复制代码
if (authenticated) {
  function setAuthUser () {}    // ✗ avoid
}

Arrow Functions 箭头函数

匿名函数或内联函数,使用箭头函数。eslint:prefer-arrow-callback arrow-spacing

js 复制代码
// 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,直接返回对象即可。 eslint:arrow-parens arrow-body-style

js 复制代码
// 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 + 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,
}));

// No implicit return with side effects
function foo(callback) {
  const val = callback();
  if (val === true) {
   console.log("hello")
  }
}

let bool = false;

// bad // 代码报错
foo(() => bool = true);

// good 这里要用对象包裹 才能省略return
foo(() => {
  bool = true;
});

如果表达式跨越多行,换行显示

js 复制代码
// 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: arrow-parens

js 复制代码
// bad
[1, 2, 3].map(x => x * x);

// good
[1, 2, 3].map((x) => x * x);

避免箭头函数(=>) 与比较运算符 (<=>=) 混淆。eslint: no-confusing-arrow

js 复制代码
// 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;
};

箭头函数体的默认不换行,或者括号包裹。eslint: implicit-arrow-linebreak

js 复制代码
// bad
(foo) =>
  bar;

(foo) =>
  (bar);

// good
(foo) => bar;
(foo) => (bar);
(foo) => (
    bar
)

Classes & Constructors 类和构造函数

始终使用Class类。代替 prototype 原型

js 复制代码
// 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继承进行扩展。

js 复制代码
// 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];
  }
}

不要定义空的构造函数或主动调用super的构造函数。eslint: no-useless-constructor

js 复制代码
// bad
class Jedi {
  constructor() {}

  getName() {
    return this.name;
  }
}

// bad
class Rey extends Jedi {
  constructor(...args) {
    super(...args);
  }
}

// good
class Rey extends Jedi {
  constructor(...args) {
    super(...args);
    this.name = 'Rey';
  }
}

子类的构造器中一定要调用 super eslint: constructor-super

js 复制代码
class Dog {
  constructor () {
    super()   // ✗ avoid
  }
}

class Dog extends Mammal {
  constructor () {
    super()   // ✓ ok
  }
}

不要扩展原生对象 。 eslint: no-extend-native

js 复制代码
Object.prototype.age = 21     // ✗ avoid

new 创建对象实例后需要赋值给变量 。 eslint: no-new

js 复制代码
new Character()                     // ✗ avoid
const character = new Character()   // ✓ ok

使用 this 前请确保 super() 已调用

eslint: no-this-before-super

js 复制代码
class Dog extends Animal {
  constructor () {
    this.legs = 4     // ✗ avoid
    super()
  }
}

禁止多余的构造器 。 eslint: no-useless-constructor

js 复制代码
class Car {
  constructor () {      // ✗ avoid
  }
}

Modules 模块

使用es6标准的import/export,不用使用 comonjs等非标准的require

js 复制代码
// 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;

不要使用通配符导入。

js 复制代码
// bad
import * as AirbnbStyleGuide from './AirbnbStyleGuide';

// good
import AirbnbStyleGuide from './AirbnbStyleGuide';

同一个包只import 一个地方。eslint: no-duplicate-imports

js 复制代码
// bad
import foo from 'foo'; 
import { named1, named2 } from 'foo';

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

不要导出可变绑定。eslint: no-mutable-exports

js 复制代码
// bad
let foo = 3;
export { foo };

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

单个导出的模块 使用默认导出。eslint:prefer-default-export

js 复制代码
// bad
export function foo() {}

// good
export default function foo() {}

将所有 import 放在最顶部。eslint: import/first

js 复制代码
// bad
import foo from 'foo';
foo.init();

import bar from 'bar';

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

foo.init();

超过多个导入应该换行。eslint: object-curly-newline

js 复制代码
// bad
import {longNameA, longNameB, longNameC, longNameD, longNameE} from 'path';

// good
import {
  longNameA,
  longNameB,
  longNameC,
  longNameD,
  longNameE,
} from 'path';

import的时候不使用扩展名,如:.js,.vue eslint: import/extensions

js 复制代码
// bad
import foo from './foo.js';
import bar from './bar.jsx';
import baz from './baz/index.jsx';

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

使用高阶函数map(),filter() 代替for-infor-of 这样的循环。eslint: no-iteratorno-restricted-syntax

js 复制代码
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;

// 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 (keeping it functional)
const increasedByOne = numbers.map((num) => num + 1);

import, export 和解构操作中,禁止赋值到同名变量 。 eslint: no-useless-rename

js 复制代码
import { config as config } from './config'     // ✗ avoid
import { config } from './config'               // ✓ ok

Properties 属性

访问属性时使用点表示法。eslint:dot-notation

js 复制代码
const people = {
  name: 'jason',
  age: 28,
};

// bad
const name = people['name'];

// good
const name = luke.name;

对象属性换行时注意统一代码风格 。 eslint: object-property-newline

js 复制代码
const user = {
  name: 'Jane Doe', age: 30,
  username: 'jdoe86'            // ✗ avoid
}

const user = { name: 'Jane Doe', age: 30, username: 'jdoe86' }    // ✓ ok

const user = {
  name: 'Jane Doe',
  age: 30,
  username: 'jdoe86'
}                                                                 // ✓ ok

使用动态变量访问属性时使用括号表示法 []

js 复制代码
const people = {
  name: 'jason',
  age: 28,
};

function getProp(prop) {
  return people[prop]; // 动态变量
}

const name = getProp('name');

Variables 变量

不要使用 undefined 来初始化变量 。 eslint: no-undef-init

js 复制代码
let name = undefined    // ✗ avoid

let name
name = 'value'          // ✓ ok

不连续声明变量,每个变量或赋值使用一个 constlet 声明。eslint: one-var

js 复制代码
// 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 也放一起定义。

js 复制代码
// 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;

将变量分配到您需要的地方,但将它们放在合理的地方。

js 复制代码
// 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;
}

不要链式变量声明+赋值。ESLint: no-multi-assign

js 复制代码
// bad
(function example() {
  let a = b = c = 1;
}());

console.log(a); // throws ReferenceError
console.log(b); // 1
console.log(c); // 1

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

console.log(a); // throws ReferenceError
console.log(b); // throws ReferenceError
console.log(c); // throws ReferenceError

// the same applies for `const`

避免使用一元递增和递减(++--)。ESLINT no-plusplus

js 复制代码
// bad

const 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

const 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;

避免在赋值中 = 之前或之后换行。如果您的赋值违反了 max-len,请用括号括起来。eslint operator-linebreak

js 复制代码
// bad
const foo =
  superLongLongLongLongLongLongLongLongFunctionName();

// bad
const foo
  = 'superLongLongLongLongLongLongLongLongString';

// good
const foo = (
  superLongLongLongLongLongLongLongLongFunctionName()
);

// good
const foo = 'superLongLongLongLongLongLongLongLongString';

不允许未使用的变量。eslint: no-unused-vars

js 复制代码
// bad
const some_unused_var = 42; 
let y = 10; // 这里没有使用上面some_unused_var
y = 5; // 这里没有使用上面some_unused_var

// Unused function arguments.
function getX(x, y) { // y没有被使用
    return x;
}

不要对变量使用 delete 操作

eslint: no-delete-var

js 复制代码
var name
delete name     // ✗ avoid

Comparison Operators & Equality 比较运算符和相等

==!= 上使用 ===!=。ESLint:EQEqEQ

js 复制代码
// bad 
const x = 100
if (x == 42) { }

const y = 'xxx'
if (y != 'xxx') { }


// good 
const x = 100
if (x === 42) { }

const y = 'xxx'
if (y !== 'xxx') { }

条件语句(如 if 语句)使用 ToBoolean 抽象方法的强制来评估其表达式,并始终遵循以下简单规则:

  • Objects evaluate to true
  • Undefined evaluates to false
  • Null evaluates to false
  • Booleans evaluate to the value of the boolean
  • Numbers evaluate to false if +0, -0, or NaN , otherwise true
  • Strings evaluate to false if an empty string '', otherwise true
js 复制代码
if ([0] && []) {
  // true
  // an array (even an empty one) is an object, objects will evaluate to true
}

对布尔值直接比较,但字符串和数字使用显式比较。

js 复制代码
// bad
if (isValid === true) {
  // ...
}

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

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

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

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

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

switch的case和default使用大括号在包裹内容 eslint: no-case-declarations

js 复制代码
// 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 {}
  }
}

三元不应嵌套,通常拆成多个,然后每个单行表达

非要分开则?: 与跟后面代码一行。eslint: no-nested-ternary文件

js 复制代码
// bad
const foo = maybe1 > maybe2
  ? "bar"
  : value1 > value2 ? "baz" : null;

// split into 2 separated ternary expressions
const maybeNull = value1 > value2 ? 'baz' : null;

// better
const foo = maybe1 > maybe2
  ? 'bar'
  : maybeNull;

// best
const foo = maybe1 > maybe2 ? 'bar' : maybeNull;

使用|| , !!, ?? 代替三元语句。eslint: no-unneeded-ternary

js 复制代码
// 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;

混合运算符时,建议判断都加上括号,||, &&分离括号。eslint: no-mixed-operators

js 复制代码
// bad
const foo = a && b < 0 || c > 0 || d + 1 === 0;

// bad
const bar = a ** b - 5 % d;

// bad
// one may be confused into thinking (a || b) && c
if (a || b && c) {
  return d;
}

// bad
const bar = a + b / c * 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;

?? 主要判断 null未定义。其他0或者 ''不应该使用。

js 复制代码
// bad
const value = 0 ?? 'default';
// returns 0, not 'default'

// bad
const value = '' ?? 'default';
// returns '', not 'default'

// good
const value = null ?? 'default';
// returns 'default'

// good
const user = {
  name: 'John',
  age: null
};
const age = user.age ?? 18;
// returns 18

代码块短则一行,多应该加上括号 eslint: nonblock-statement-body-position

js 复制代码
// bad
if (test)
  return false;

// good
if (test) return false;

// good
if (test) {
  return false;
}

// bad
function foo() { return false; }

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

如果您使用带有 ifelse 的多行块, else 不独立一行 。eslint: brace-style

js 复制代码
// bad
if (test) {
  thing1();
  thing2();
}
else {
  thing3();
}

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

一元运算符后面跟一个空格 。 eslint: space-unary-ops

js 复制代码
typeof!admin        // ✗ avoid
typeof !admin        // ✓ ok

Control Statements 控制语句

条件多应该换行显示,判断符号在前面

js 复制代码
// bad
if ((foo === 123 || bar === 'abc') && doesItLookGoodWhenItBecomesThatLong() && isThisReallyHappening()) {
  thing1();
}

// bad
if (foo === 123 &&
  bar === 'abc') {
  thing1();
}

// bad
if (foo === 123
  && bar === 'abc') {
  thing1();
}

// bad
if (
  foo === 123 &&
  bar === 'abc'
) {
  thing1();
}

// good
if (
  foo === 123
  && bar === 'abc'
) {
  thing1();
}

// good
if (
  (foo === 123 || bar === 'abc')
  && doesItLookGoodWhenItBecomesThatLong()
  && isThisReallyHappening()
) {
  thing1();
}

// good
if (foo === 123 && bar === 'abc') {
  thing1();
}

不要使用选择运算符代替控制语句。

js 复制代码
// bad
!isRunning && startRunning();

// good
if (!isRunning) {
  startRunning();
}

switch 一定要使用 break 来将条件分支正常中断 。 eslint: no-fallthrough

js 复制代码
switch (filter) {
  case 1:
    doSomething()    // ✗ avoid
  case 2:
    doSomethingElse()
}

switch (filter) {
  case 1:
    doSomething()
    break           // ✓ ok
  case 2:
    doSomethingElse()
}

switch (filter) {
  case 1:
    doSomething()
    // fallthrough  // ✓ ok
  case 2:
    doSomethingElse()
}

finally 代码块中不要再改变程序执行流程 。 eslint: no-unsafe-finally

js 复制代码
try {
  // ...
} catch (e) {
  // ...
} finally {
  return 42     // ✗ avoid
}

请书写优雅的条件语句(avoid Yoda conditions) 。 eslint: yoda

js 复制代码
if (42 === age) { }    // ✗ avoid
if (age === 42) { }    // ✓ ok

Comments 注释

对多行注释使用 /** ... */

js 复制代码
// bad
// make() returns a new element
// based on the passed in tag name
//
// @param {String} tag
// @return {Element} element
function make(tag) {

  // ...

  return element;
}

// good
/**
  * make() returns a new element
  * based on the passed-in tag name
  */
function make(tag) {

  // ...

  return element;
}

注释放在行上方

js 复制代码
// bad
const active = true;  // is current tab

// good
// is current tab
const active = true;

// bad
function getType() {
  console.log('fetching type...');
  // set the default type to 'no type'
  const type = this.type || 'no type';

  return type;
}

// good
function getType() {
  console.log('fetching type...');

  // set the default type to 'no type'
  const type = this.type || 'no type';

  return type;
}

// also good
function getType() {
  // set the default type to 'no type'
  const type = this.type || 'no type';

  return type;
}

注释前加空格。eslint: spaced-comment

js 复制代码
// bad
//is current tab
const active = true;

// good
// is current tab
const active = true;

// bad
/**
  *make() returns a new element
  *based on the passed-in tag name
  */
function make(tag) {

  // ...

  return element;
}

// good
/**
  * make() returns a new element
  * based on the passed-in tag name
  */
function make(tag) {

  // ...

  return element;
}

使用 FIXME: 注释问题。

js 复制代码
class Calculator extends Abacus {
  constructor() {
    super();

    // FIXME: shouldn't use a global here
    total = 0;
  }
}

使用 TODO: 注释问题的解决方案。

js 复制代码
class Calculator extends Abacus {
  constructor() {
    super();

    // TODO: total should be configurable by an options param
    this.total = 0;
  }
}

如果有更好的实现,尽量不要使用三元表达式

eslint: no-unneeded-ternary

js 复制代码
let score = val ? val : 0     // ✗ avoid
let score = val || 0          // ✓ ok

Whitespace 空白

使用设置为 2 个空格的软制表符(空格字符)。eslint: indent

js 复制代码
// bad
function foo() {
∙∙∙∙let name;
}

// bad
function bar() {
∙let name;
}

// good
function baz() {
∙∙let name;
}

在前大括号前放置 1 个空格。eslint: space-before-blocks

js 复制代码
// 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',
});

单行代码块两边加空格 。 eslint: block-spacing

js 复制代码
// bad
function foo () {return true}
// good
function foo () { return true }

在控制语句(ifwhile 等)的左括号前放置 1 个空格。在函数调用和声明中,参数列表和函数名称之间不要放置空格。eslint: keyword-spacing

js 复制代码
// bad
if(isJedi) {
  fight ();
}

// good
if (isJedi) {
  fight();
}

// bad
function fight () {
  console.log ('Swooosh!');
}

// good
function fight() {
  console.log('Swooosh!');
}

用空格来衬托运算符。eslint: space-infix-ops

js 复制代码
// bad
const x=y+5;

// good
const x = y + 5;

使用单个换行符结束文件。ESLint:eol-last

js 复制代码
// bad
import { es6 } from './AirbnbStyleGuide';
  // ...
export default es6;
js 复制代码
// bad
import { es6 } from './AirbnbStyleGuide';
  // ...
export default es6;↵
↵
js 复制代码
// good
import { es6 } from './AirbnbStyleGuide';
  // ...
export default es6;↵

在块之后和下一个语句之前留一个空行。

js 复制代码
// bad
if (foo) {
  return bar;
}
return baz;

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

return baz;

// bad
const obj = {
  foo() {
  },
  bar() {
  },
};
return obj;

// good
const obj = {
  foo() {
  },

  bar() {
  },
};

return obj;

// bad
const arr = [
  function foo() {
  },
  function bar() {
  },
];
return arr;

// good
const arr = [
  function foo() {
  },

  function bar() {
  },
];

return arr;

在块里不要多余的空行。eslint: padded-blocks eslint: no-multiple-empty-lines

js 复制代码
// bad
function bar() {

  console.log(foo);

}

// bad
if (baz) {

  console.log(quux);
} else {
  console.log(foo);

}

// bad
class Foo {

  constructor(bar) {
    this.bar = bar;
  }
}

// good
function bar() {
  console.log(foo);
}

// good
if (baz) {
  console.log(quux);
} else {
  console.log(foo);
}

不要在括号内添加空格。eslint: space-in-parens

js 复制代码
// bad
function bar( foo ) {
  return foo;
}

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

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

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

不要在括号内添加空格。eslint: array-bracket-spacing

js 复制代码
// bad
const foo = [ 1, 2, 3 ];
console.log(foo[ 0 ]);

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

在大括号内添加空格。eslint: object-curly-spacing

js 复制代码
// bad
const foo = {clark: 'kent'};

// good
const foo = { clark: 'kent' };

代码过长,需要换行。 ESLint:MAX-LEN

js 复制代码
// 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.'));

逗号前不用空格,逗号后使用空格。eslint: comma-spacing

js 复制代码
// bad 
const arr = [1 , 2];
var foo = 1,bar = 2;
// good 
const arr = [1, 2];
var foo = 1, bar = 2;

字面量对象属性的:后面要有空格 。eslint: key-spacing

js 复制代码
// bad
const obj = { foo : 42 };
const obj2 = { foo:42 };

// good
const obj = { foo: 42 };

避免在行尾出现尾随空格。eslint: no-trailing-spaces

js 复制代码
// bad - multiple empty lines
const x = 1;. // .代表空格

// good
const x = 1;

除了缩进,不要使用多个空格 。 eslint: no-multi-spaces

js 复制代码
const id =    1234    // ✗ avoid
const id = 1234       // ✓ ok

遇到分号时空格要后留前不留 。 eslint: semi-spacing

js 复制代码
for (let i = 0 ;i < items.length ;i++) {...}    // ✗ avoid
for (let i = 0; i < items.length; i++) {...}    // ✓ ok

Commas 逗号

数组/对象/属性的逗号都应该在后面。 eslint: comma-style

js 复制代码
// bad
const story = [
    once
  , upon
  , aTime
];

// good
const story = [
  once,
  upon,
  aTime,
];

// bad
const hero = {
    firstName: 'Ada'
  , lastName: 'Lovelace'
  , birthYear: 1815
  , superPower: 'computers'
};

// good
const hero = {
  firstName: 'Ada',
  lastName: 'Lovelace',
  birthYear: 1815,
  superPower: 'computers',
};

对象/数组/属性最后一个元素都多加一个逗号 eslint: comma-dangle

js 复制代码
// bad
const hero = {
  firstName: 'Dana',
  lastName: 'Scully'
};

const heroes = [
  'Batman',
  'Superman'
];

// good
const hero = {
  firstName: 'Dana',
  lastName: 'Scully',
};

const heroes = [
  'Batman',
  'Superman',
];

// bad
function createHero(
  firstName,
  lastName,
  inventorOf
) {
  // does nothing
}

// good
function createHero(
  firstName,
  lastName,
  inventorOf,
) {
  // does nothing
}

// good (note that a comma must not appear after a "rest" element)
function createHero(
  firstName,
  lastName,
  inventorOf,
  ...heroArgs
) {
  // does nothing
}

// bad
createHero(
  firstName,
  lastName,
  inventorOf
);

// good
createHero(
  firstName,
  lastName,
  inventorOf,
);

// good (note that a comma must not appear after a "rest" element)
createHero(
  firstName,
  lastName,
  inventorOf,
  ...heroArgs
);

Type Casting & Coercion 类型转换

字符串转化用String(xx), 不用new String()obj.toString():eslint:no-new-wrappers

js 复制代码
const reviewScore = 9;

// bad
const totalScore = new String(reviewScore); 
// bad
const totalScore = reviewScore + ''; 
// bad
const totalScore = reviewScore.toString(); 

// good
const totalScore = String(this.reviewScore);

Numbers:使用 Number 进行类型转换。 parseInt('200', 10)要传入第二个进制参数。ESLint: no-new-wrappers

js 复制代码
// bad
const val = parseInt(inputValue);

// good
const val = Number(inputValue);

// good
const val = parseInt(inputValue, 10);

不使用 new Boolean()创建布尔值:eslint:no-new-wrappers

js 复制代码
const age = 0;

// bad
const hasAge = new Boolean(age);

// good
const hasAge = Boolean(age);

// best
const hasAge = !!age;

Naming Conventions 命名约定

避免使用单字母名称。你的命名要具有描述性。eslint:id-length

js 复制代码
// bad
function q() {
  // ...
}

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

命名对象、函数和实例时使用驼峰命名法。eslint: camelcase

js 复制代码
// bad
const OBJEcttsssss = {};
const this_is_my_object = {};
function c() {}

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

仅在命名构造函数或类时使用 PascalCase。ESLint: new-cap

js 复制代码
// bad
function user(options) {
  this.name = options.name;
}

const bad = new user({
  name: 'nope',
});

// good
class User {
  constructor(options) {
    this.name = options.name;
  }
}

const good = new User({
  name: 'yup',
});

变量前后不要加 __xxxx__下划线。eslint: no-underscore-dangle

js 复制代码
// bad
this.__firstName__ = 'Panda';
this.firstName_ = 'Panda';
this._firstName = 'Panda';

// good
this.firstName = 'Panda';

不要保存对this引用。使用箭头函数或 Function#bind代替。

js 复制代码
// bad
function foo() {
  const self = this;
  return function () {
    console.log(self);
  };
}

// bad
function foo() {
  const that = this;
  return function () {
    console.log(that);
  };
}

// good
function foo() {
  return () => {
    console.log(this);
  };
}

导出默认函数时使用驼峰命名法。您的文件名应与函数名称相同。

js 复制代码
function makeStyleGuide() {
  // ...
}

export default makeStyleGuide;

// 文件名 makeStyleGuide.js

导出构造函数/类/单例/函数库/裸对象时使用 PascalCase。

js 复制代码
// 构造函数
export default function MyConstructor(name) {
  this.name = name;
}

// 类 
export default class UserProfile {} 

// 单例 
export default  Logger = { log(msg) { console.log(msg); } }; 

// 裸对象
export default const AppConfig = {
  API_URL: 'https://api.example.com',
  ENV: 'production',
}; 
 

首字母缩略词和首字母缩略词应始终全部大写或全部小写。

js 复制代码
// bad
import SmsContainer from './containers/SmsContainer';

// bad
const HttpRequests = [
  // ...
];

// good
import SMSContainer from './containers/SMSContainer';

// good
const HTTPRequests = [
  // ...
];

// also good
const httpRequests = [
  // ...
];

// best
import TextMessageContainer from './containers/TextMessageContainer';

// best
const requests = [
  // ...
];

只有当常量直接导出时key值大写。如果导出是对象中的key 还是小写。

js 复制代码
// bad
const PRIVATE_VARIABLE = 'should not be unnecessarily uppercased within a file';

// bad
export const THING_TO_BE_CHANGED = 'should obviously not be uppercased';

// bad
export let REASSIGNABLE_VARIABLE = 'do not use let with uppercase variables';

// ---

// bad
export const apiKey = 'SOMEKEY';

// good
export const API_KEY = 'SOMEKEY';

// ---

// bad - 这里不应该大写
export const MAPPING = {
  KEY: 'value'
};

// good
export const MAPPING = {
  key: 'value',
};

不要使用 JavaScript getter/setter,改用 getVal()setVal('hello')

js 复制代码
// bad
class Dragon {
  get age() {
    // ...
  }

  set age(value) {
    // ...
  }
}

// good
class Dragon {
  getAge() {
    // ...
  }

  setAge(value) {
    // ...
  }
}

属性/方法是布尔值 ,使用 isVal()hasVal()定义

js 复制代码
// bad
if (!dragon.age()) {
  return false;
}

// good
if (!dragon.hasAge()) {
  return false;
}

Events 事件

通过对象做事件的参数。

js 复制代码
// bad
$(this).trigger('listingUpdated', listing.id);

// good
$(this).trigger('listingUpdated', { listingID: listing.id });
 
// bad
$(this).on('listingUpdated', (e, listingID) => {
  // do something with listingID
});
// good
$(this).on('listingUpdated', (e, data) => {
  // do something with data.listingID
});

Standard Library 标准库与其他

使用 Number.isNaN 而不是全局 isNaN。eslint: no-restricted-globals

js 复制代码
// bad
isNaN('1.2'); // false
isNaN('1.2.3'); // true

// good
Number.isNaN('1.2.3'); // false
Number.isNaN(Number('1.2.3')); // true

使用浏览器全局变量时加上 window. 前缀。 documentconsolenavigator 除外。

eslint: no-undef

js 复制代码
window.alert('hi')   // ✓ ok

不要使用 debugger 。 eslint: no-debugger

js 复制代码
function sum (a, b) {
  debugger      // ✗ avoid
  return a + b
}

不要省去小数点前面的0 。 eslint: no-floating-decimal

js 复制代码
const discount = .5      // ✗ avoid
const discount = 0.5     // ✓ ok

不要使用标签语句

eslint: no-labels

js 复制代码
label:
  while (true) {
    break label     // ✗ avoid
  }

使用 __dirname__filename 时尽量避免使用字符串拼接

eslint: no-path-concat

js 复制代码
const pathToFile = __dirname + '/app.js'            // ✗ avoid
const pathToFile = path.join(__dirname, 'app.js')   // ✓ ok

使用 getPrototypeOf 来替代 __proto__

eslint: no-proto

js 复制代码
const foo = obj.__proto__               // ✗ avoid
const foo = Object.getPrototypeOf(obj)  // ✓ ok

不要随意更改关键字的值 。 eslint: no-shadow-restricted-names

js 复制代码
let undefined = 'value'     // ✗ avoid

throw 抛错时,抛出 Error 对象而不是字符串

eslint: no-throw-literal

js 复制代码
throw 'error'               // ✗ avoid
throw new Error('error')    // ✓ ok

避免不必要的 .call().apply()

eslint: no-useless-call

js 复制代码
sum.call(null, 1, 2, 3)   // ✗ avoid

检查 NaN 的正确姿势是使用 isNaN()

eslint: use-isnan

js 复制代码
if (price === NaN) { }      // ✗ avoid
if (isNaN(price)) { }       // ✓ ok
相关推荐
小高0072 小时前
🔍ECMAScript 2025 有哪些新特性?
前端·javascript
正义的大古2 小时前
OpenLayers地图交互 -- 章节十七:键盘缩放交互详解
javascript·vue.js·openlayers
Hashan2 小时前
elpis-core:基于 Koa 的轻量级 Web 应用框架
前端·javascript·node.js
前端Hardy3 小时前
轻松搞定JavaScript数组方法,面试被问直接答!
前端·javascript·面试
云枫晖3 小时前
手写Promise-catch和finally
前端·javascript
薄雾晚晴3 小时前
大屏开发实战:封装自动判断、无缝衔接的文字滚动组件,告别文本截断烦恼
前端·javascript·vue.js
Beginner x_u3 小时前
前端八股文 Vue上
前端·javascript·vue.js·八股文
Strawberry_rabbit3 小时前
Docker
前端
江拥羡橙3 小时前
JavaScript异步编程:告别回调地狱,拥抱Promise async/await
开发语言·javascript·ecmascript·promise·async/await