定义变量
变量命名尽量减少缩写的情况,要做到见名知意(无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 抽象方法强制计算它们的表达式,并始终遵循以下简单规则:
| 表达式**** | 值**** |
|---|---|
| undefined | false |
| null | false |
| boolean | boolean |
| object | true |
| 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.name 等路由参数判断业务,尽量通过差异化属性来判断;
· 页面返回尽量使用router.go(-1) ,因为特殊逻辑无法使用的,应该使用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维护;