代码规范记录

68 阅读5分钟

定义变量

变量命名尽量减少缩写的情况,要做到见名知意(无eslint)

// bad

let rContent = 'willen'; 

 

// good 名字上就看懂

let firstName = 'jackie'; 

 

// bad 从命名无法知道返回值类型

function showFriendsList() {....} // // 无法辨别函数意图,返回的是一个数组,还是一个对象,还是true or false?

 

// good 明确函数意图,对于返回true or false的函数,最好以should/is/can/has开头

function shouldShowFriendsList() {...}

function isEmpty() {...}

function canCreateDocuments() {...}

function hasLicense() {...}

function sendEmailToUser(user) {.... } //动词开头,函数意图就很明显

优先使用const声明变量,如果变量需要重新赋值应使用let声明,禁止使用var声明变量。const、let是块级作用域,var是函数作用域,并且var存在变量提升。

// bad

var a = 1;

var b = 2;

 

// good

const a = 1;

const b = 2;

 

// bad

var count = 1;

if (true) {

  count += 1;

}

 

// good, use the let.

let count = 1;

if (true) {

  count += 1;

}

在你需要的地方声明变量,但是要放在合理的位置(无eslint)

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

// bad 对于求值获取的变量,没有兜底

const { data } = getApiRequest();

data.map((s) => s.id); //没有考虑data异常的情况,代码一跑就爆炸

 

// good 对于求值变量,做好兜底

const { data = [] } = getApiRequest();

data.map((s) => s?.id);

## [声明对象](#声明对象)****

创建对象应该使用字面量声明,而不是使用new对象的方式

// bad

const item = new Object();

 

// good

const item = {};

创建对象时属性名时动态的情况,使用计算属性声明,这样可以在声明对象的时候定义所有属性(无eslint)

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;

  },

};

声明对象时,方法要缩写,属性也要缩写。这样更加简短

// bad

const atom = {

  value: 1,

 

  addValue: function (value) {

    return atom.value + value;

  },

};

 

// good

const atom = {

  value: 1,

 

  addValue(value) {

    return atom.value + value;

  },

};

 

const lukeSkywalker = 'Luke Skywalker';

 

// bad

const obj = {

  lukeSkywalker: lukeSkywalker,

};

 

// good

const obj = {

  lukeSkywalker,

};

缩写属性要置于对象非缩写属性前面(无eslint)

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引擎优化

// 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,这些方法名不是js保留字,可以被重写,并且在使用Object.create(null)创建的对象时,执行会报错。

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

console.log(has.call(object, key));

/* or */

import has from 'has'; // https://www.npmjs.com/package/has

console.log(has(object, key));

浅拷贝使用扩展运算符...,而不是使用Object.assign([prefer-object-spread](https://eslint.org/docs/rules/prefer-object-spread) 不做强制要求)

// very bad

const original = { a: 1, b: 2 };

const copy = Object.assign(original, { c: 3 }); // 更改了原对象

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 }

数组

使用字面量创建数字,而不是使用new Array()的方式, 当数组指定大小时除外,可使用new Array(size) 创建固定长度的数组

// bad

const items = new Array();

 

// good

const items = [];

添加数组使用push方法,而不是直接赋值的方式(无eslint)

const someStack = [];

 

// bad

someStack[someStack.length] = 'abracadabra';

 

// good

someStack.push('abracadabra');

使用扩展运算符...copy数组(无eslint)

// bad

const len = items.length;

const itemsCopy = [];

let i;

 

for (i = 0; i < len; i += 1) {

  itemsCopy[i] = items[i];

}

 

// good

const itemsCopy = [...items];

转换可枚举对象使用扩展运算符...,不使用Array.from(无eslint)

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

 

// good

const nodes = Array.from(foo);

 

// best

const nodes = [...foo];

类数组对象转为数组使用Array.from(无eslint)

const arrLike = { 0: 'foo', 1: 'bar', 2: 'baz', length: 3 };

 

// bad

const arr = Array.prototype.slice.call(arrLike);

 

// good

const arr = Array.from(arrLike);

如果一个数组有多行,则在打开和关闭数组方括号之后使用换行符

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

];

解构

使用对象解构获取属性。避免为属性创建临时引用,以及避免对对象的重复访问。重复对象访问会产生更多的重复代码并创造更多出错的机会。数组类似

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

function processInput(input) {

  // then a miracle occurs

  return [left, right, top, bottom];

}

 

// the caller needs to think about the order of return data

const [left, __, top] = processInput(input);

 

// good

function processInput(input) {

  // then a miracle occurs

  return { left, right, top, bottom };

}

 

// the caller selects only the data they need

const { left, top } = processInput(input);

字符串

js代码字符串使用单引号

// bad

const name = "Capt. Janeway";

 

// bad - template literals should contain interpolation or newlines

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

}

禁用eval() 禁止无意义的字符串转义

// bad

const foo = '\'this\' \i\s \"quoted\"';

 

// good

const foo = '\'this\' is "quoted"';

const foo = `my name is '${name}'`;

类型转换

string类型转换

 

// bad

const totalScore = new String(this.reviewScore); // typeof totalScore is "object" not "string"

 

// bad

const totalScore = this.reviewScore.toString(); // 不保证返回string

 

// good

const totalScore = String(this.reviewScore);

// 有的规范推荐`+` 空字符串的形式转换

number类型转换,用 Number 做类型转换,parseInt转换string常需要带上基数

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

boolean类型转换

const age = 0;

 

// bad

const hasAge = new Boolean(age);

 

// good

const hasAge = Boolean(age);

 

// best

const hasAge = !!age;

函数****

立即执行函数使用括号包裹

// bad

const a = function () {

  console.log('Welcome to the Internet. Please follow me.');

  return '';

}()

 

 

// good

// immediately-invoked function expression (IIFE)

const a = (function () {

  console.log('Welcome to the Internet. Please follow me.');

  return '';

}());

不要在非函数块(if、 while 等)中声明函数。而是将函数赋给一个变量。块内直接声明函数不同浏览器解析方式不同

// bad

if (currentUser) {

  function test() {

    console.log('Nope.');

  }

}

 

// good

let test;

if (currentUser) {

  test = () => {

    console.log('Yup.');

  };

}

不要把函数参数名设置为arguments,这样会覆盖arguments对象(无eslint)

// bad

function foo(name, options, arguments) {

  // ...

}

 

// good

function foo(name, options, args) {

  // ...

}

函数使用参数默认值,而不要在函数体内设置默认值.(无eslint)

// 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 = {}) {

  // ...

}

禁止使用new Function的方式创建函数

// bad

var add = new Function('a', 'b', 'return a + b');

 

// still bad

var subtract = Function('a', 'b', 'return a - b');

不要修改函数参数,更不要重新赋值(可能导致一些意外行为,还可能导致优化问题,特别是在v8中)(经讨论因历史代码原因,eslint不启用该规则校验)

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

  // ...

}

使用扩展运算符而不是使用apply

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

箭头函数

使用匿名函数时,例如在回调和函数作为参数或返回值时,使用箭头函数代替

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

});

箭头函数代码样式,箭头函数参数必须带括号(添加删除时最小化diff),如果函数体由一个返回表达式的语句组成而没有副作用,那么省略大括号并使用隐式返回。否则,保留大括号并使用 return 语句(--)

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

    // Do something if callback returns true

  }

}

 

let bool = false;

 

// bad

foo(() => bool = true);

 

// good

foo(() => {

  bool = true;

});

箭头函数体返回表达式跨行时使用括号包裹,更容易阅读(无)

// bad

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

    httpMagicObjectWithAVeryLongName,

    httpMethod,

  )

);

 

// good

['get', 'post', 'put'].map((httpMethod) => (

  Object.prototype.hasOwnProperty.call(

    httpMagicObjectWithAVeryLongName,

    httpMethod,

  )

));

避免箭头函数语法=>和>= 、<= 比较运算符混淆

// 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,不要使用原型构造。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继承(无)

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

类的方法如果没有访问内部属性,应设置为静态方法

// bad

class Foo {

  bar() {

    console.log('bar');

  }

}

 

// good - this is used

class Foo {

  bar() {

    console.log(this.bar);

  }

}

 

// good - constructor is exempt

class Foo {

  constructor() {

    // ...

  }

}

 

// good - static methods aren't expected to use this

class Foo {

  static bar() {

    console.log('bar');

  }

}

模块****

使用es6的模块语法,不要使用其他非标准的模块语法

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

不要使用通配符导入

// bad

import * as AirbnbStyleGuide from './AirbnbStyleGuide';

 

// good

import AirbnbStyleGuide from './AirbnbStyleGuide';

尽量导出常量

// bad

let foo = 3;

export { foo };

 

// good

const foo = 3;

export { foo };

模块中只有一条导出时使用export default导出

// bad

export function foo() {}

 

// good

export default function foo() {}

全部导出结束后,再使用导出内容

// bad

import foo from 'foo';

foo.init();

 

import bar from 'bar';

 

// good

import foo from 'foo';

import bar from 'bar';

 

foo.init();

多行导入像 多行数组或者对象一样换行展示

// bad

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

 

// good

import {

  longNameA,

  longNameB,

  longNameC,

  longNameD,

  longNameE,

} from 'path';

迭代器与生成器

使用js高级函数mapeveryforeach等替代for-in 和 for-of,优先函数式编程,仅遍历建议使用foreach,不要使用map,当要返回新的数组时使用map

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

不要使用生成器函数,转义es5有缺陷

属性

常规属性使用原点访问属性,而不是使用[]

const luke = {

  jedi: true,

  age: 28,

};

 

// bad

const isJedi = luke['jedi'];

 

// good

const isJedi = luke.jedi;

变量属性使用[]访问

const luke = {

  jedi: true,

  age: 28,

};

 

function getProp(prop) {

  return luke[prop];

}

 

const isJedi = getProp('jedi');

不要链式变量赋值,会创建隐式全局变量

// 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); // 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不校验该规则) 根据 eslint 文档,一元递增和递减语句受到自动分号插入的限制,并且可能导致应用程序中的值递增或递减的静默错误。使用 num + = 1而不是 num++ 或 num++ 这样的语句来更改值也更有表现力。禁用一元递增和递减语句还可以防止无意中提前递增/提前递减值,这也可能导致程序中出现意外行为。


var i = 10;

var j = 20;

 

i ++

j

// i = 11, j = 20

 

var i = 10;

var j = 20;

 

i

++

j

// i = 10, j = 21

 

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

前后禁止换行

// bad

const foo =

  superLongLongLongLongLongLongLongLongFunctionName();

 

// bad

const foo

  = 'superLongLongLongLongLongLongLongLongString';

 

// good

const foo = (

  superLongLongLongLongLongLongLongLongFunctionName()

);

 

// good

const foo = 'superLongLongLongLongLongLongLongLongString';

禁止存在未使用的变量

// bad

 

var some_unused_var = 42;

 

// Write-only variables are not considered as used.

var y = 10;

y = 5;

 

// A read for a modification of itself is not considered as used.

var z = 0;

z = z + 1;

 

// Unused function arguments.

function getX(x, y) {

    return x;

}

 

// good

 

function getXPlusY(x, y) {

  return x + y;

}

 

var x = 1;

var y = a + 2;

 

alert(getXPlusY(x, y));

 

// 'type' is ignored even if unused because it has a rest property sibling.

// This is a form of extracting an object that omits the specified keys.

var { type, ...coords } = data;

// 'coords' is now the 'data' object without its 'type' property.

其他

使用===、!==判断是否相等,而不要使用==、!=进行判断, 仅当判断null 或undefined 时,允许使用 ==null

诸如 if 语句之类的条件语句使用 ToBoolean 抽象方法强制计算它们的表达式,并始终遵循以下简单规则:

表达式********
undefinedfalse
nullfalse
booleanboolean
objecttrue
number+0,-0,NaN 是false,其他为true
string''是false,其他为true

if ([0] && []) {

  // true

  // an array (even an empty one) is an object, objects will evaluate to true

}

switch case语法,case与default后增加括号形成代码块,防止访问未初始化的词法绑定以及跨大小写子句访问提升的函数

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

 

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

避免不必要的三元表达式

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

混合表达式,将他们分组放在括号内更容易阅读

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

if else代码格式

// bad

if (test) {

  thing1();

  thing2();

}

else {

  thing3();

}

 

// good

if (test) {

  thing1();

  thing2();

} else {

  thing3();

}

如果if语句执行了return ,那么不需要写else了

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

  }

}

不要再循环中使用await,而是使用Promise.all

// bad

async function foo(things) {

  const results = [];

  for (const thing of things) {

    // Bad: each loop iteration is delayed until the entire asynchronous operation completes

    results.push(await bar(thing));

  }

  return baz(results);

}

 

// good

async function foo(things) {

  const results = [];

  for (const thing of things) {

    // Good: all asynchronous operations are immediately started.

    results.push(bar(thing));

  }

  // Now that all the asynchronous operations are running, here we wait until they all complete.

  return baz(await Promise.all(results));

}

代码样式

用小驼峰式命名你的对象、函数、实例

// bad

const OBJEcttsssss = {};

const this_is_my_object = {};

function c() {}

 

// good

const thisIsMyObject = {};

function thisIsMyFunction() {}

用大驼峰式命名类

// 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',

});

当你export-default一个函数时,函数名用小驼峰,文件名需要和函数名一致

function makeStyleGuide() {

  // ...

}

 

export default makeStyleGuide;

当你export一个结构体/类/单例/函数库/对象 时用大驼峰。

// bad

const AirbnbStyleGuide = {

  es6: {

  }

};

 

export default AirbnbStyleGuide;

如果属性/方法是boolean, 用 isVal() 或 hasVal()

// bad

if (!dragon.age()) {

  return false;

}

 

// good

if (!dragon.hasAge()) {

  return false;

}

注释加空格,更容易阅读

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

}

空格

缩进,1tab=2空格

// bad

function foo() {

∙∙∙∙let name;

}

 

// bad

function bar() {

∙let name;

}

 

// good

function baz() {

∙∙let name;

}

代码块前面添加空格 关键词前后加空格

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

在对象的字面量属性中, :与 value 之间要有空格,与key之间无空格

// bad

const obj = { "foo" : 42 };

const obj2 = { "foo":42 };

 

// good

const obj = {

  foo: 42

};

不要前置逗号

// bad

const story = [

    once

  , upon

  , aTime

];

 

// good

const story = [

  once,

  upon,

  aTime

];

对象字面量多行属性时,要末尾逗号

// bad

const story = [

  once,

  upon,

  aTime

];

 

// good

const story = [

  once,

  upon,

  aTime,

];

行末要加分号

// bad

(function () {

  const name = 'Skywalker'

  return name

})()

 

// good

(function () {

  const name = 'Skywalker';

  return name;

}());

需要重新确认的代码样式****

· 函数空格;(建议保持原状);结论: 保持原规则,不采用airbnb规则

· 尾随逗号;结论:采用

· 严格缩进; 结论:采用

· 箭头函数仅有一个参数时,是否加括号; 结论:采用

· 导入后缀问题, js, vue. jsx文件,是否要求必须有后缀或者必须没有后缀;结论:采用airbnb规则,js,ts,jsx,tsx,mjs文件导入不写后缀,其他文件必须写后缀;

· 最后一个导入语句后面,是否必须插入一个空行;结论:采用

· 导入顺序是否增加限制;(node> node_modules > 自定义);结论:采用

· require 引用是否必须要在顶部定义,不允许在代码中使用;放在顶部容易识别依赖项,同步加载问题可能有性能问题; 结论:不采用airbnb规则,去除限制,可在任意位置使用,同时不校验‘动态引用’

· 对象字面表示,解构,导入,导出多行的换行规则;结论:采用airbnb规则

· for in, for of 语句是否直接禁用;结论:不禁用for in,for of

· 自增运算符是否禁用,i++ i-- 等;结论:不禁用自增运算符

· 单行字符数量是否限制;结论:不采用

· 短路计算是否禁用,类似还有三元运算符计算;结论:不禁用短路计算

· 属性命名_ 下划线开头;结论:不采用

· 运算符换行规则, 是否强制运算符前后的换行规则 + after换行规则;结论:采用部分,在运算符后面插入换行符

· 箭头函数体是否禁止换行; 结论:不采用

// bad

Exportmanage: () =>

  import(

    /* webpackChunkName: "chunk-exportmanage" */ '@/components/BI/dashboard/components/Exportmanage.vue'

  )

// good

Exportmanage: () => import(

  /* webpackChunkName: "chunk-exportmanage" */ '@/components/BI/dashboard/components/Exportmanage.vue'

)

 

VUE规范****

Style Guide - Vue 中文文档(@印记中文) https://docschina.org/

其他建议****

 

· 非页面组件内不要使用route.query route.query route.name 等路由参数判断业务,尽量通过差异化属性来判断;

· 页面返回尽量使用router.back() router.back() router.go(-1) ,因为特殊逻辑无法使用的,应该使用router.replace 而不是router.replace 而不是router.push ,避免浏览器页面栈混乱;

· vue组件内非scope 的样式,不应该维护在组件内部,应该提取到某个公共样式文件;

· 不要将和渲染无关的数据放在data 中, 对于肯定无变化的数据,例如部分选择框的选项,可使用Object.freeze 包裹,避免无意义的双向绑定;

· 组件销毁前,要手动销毁 如全局的事件监听器,setInterval,echarts,highcharts,事件bus等; 这里推荐hook的写法,可以将声明与销毁放在一个代码块中维护;

window.addEventListener('click', this.handleClickWindow);

this.$once('hook:beforeDestroy', () => {

  window.removeEventListener('click', this.handleClickWindow);

});

· 模块之间mixin相互引用问题,抽离顶级mixin,避免模块间mixin相互引用问题。mixin层级过深问题,mixin层级尽量不要超过3级,可读性太差。

· 导出配置文件,可以考虑导出方法返回配置的方式,deepclone太多了。

· 清除事件bus,要清除具体的事件及回调方法,类似的还有pubsub,事件监听。

// bad

this.$bus.off('close');

// good

this.$bus.off('close', this.close);

· 组件数据传递,简单功能尽量保持 Props向下传递,事件向上传递的原则,提供良好的 API 和 独立性,复杂功能可使用$refs,vuex维护;