// good
switch (variable) {
case '1':
// do...
break;
case '2':
// do...
break;
default:
// do...
}
// bad
switch (variable) {
case '1':
// do...
break;
case '2':
// do...
break;
default:
// do...
}
// good
function foo() {
let html = `
`;
}
// good
function greeting(name) {
return 'Hello, \n'
+ `${name.firstName} ${name.lastName}`;
}
// bad
function greeting(name) {
return `Hello,
${name.firstName} ${name.lastName}`;
}
// good
let a = !arr.length;
a++;
a = b + c;
// bad
let a =!arr.length;
a ++;
a = b+c;
// good
if (condition) {
}
while (condition) {
}
function funcName() {
}
// bad
if (condition){
}
while (condition){
}
function funcName(){
}
// good
if (condition) {
}
while (condition) {
}
(function () {
})();
// bad
if(condition) {
}
while(condition) {
}
(function() {
})();
// good
const obj = {
a: 1,
b: 2,
c: 3,
};
// bad
const obj = {
a : 1,
b:2,
c :3,
};
// good
function funcName() {
}
const funcName = function funcName() {
};
funcName();
// bad
function funcName () {
}
const funcName = function funcName () {
};
funcName ();
// good
callFunc(a, b);
for (let i = 0; i < length; i++) {
// xxx
}
// bad
callFunc(a , b) ;
for (let i = 0;i < length;i++) {
// xxx
}
// good
callFunc(param1, param2, param3);
const arr2 = [1, 2, 3];
save(this.list[this.indexes[i]]);
needIncream && (variable += increament);
if (num > list.length) {
}
while (len--) {
}
// bad
callFunc( param1, param2, param3 );
const arr2 = [ 1, 2, 3 ];
save( this.list[ this.indexes[ i ] ] );
needIncreament && ( variable += increament );
if ( num > list.length ) {
}
while ( len-- ) {
}
// good
function* caller() {
yield 'a';
yield* callee();
yield 'd';
}
// bad
function * caller() {
yield 'a';
yield *callee();
yield 'd';
}
// good
// simple object literals
const obj = { foo: 'bar' };
// nested object literals
const obj = { foo: { zoo: 'bar' } };
// destructuring assignment (EcmaScript 6)
const { x, y } = y;
// import/export declarations (EcmaScript 6)
import { foo } from 'bar';
export { foo };
// bad
// simple object literals
const obj = {foo: 'bar'};
// nested object literals
const obj = {foo: { zoo: 'bar' }};
// destructuring assignment (EcmaScript 6)
const {x, y} = y;
// import/export declarations (EcmaScript 6)
import {foo} from 'bar';
export {foo};
// good
console.log('a');
console.log('b');
// bad
console.log('a');console.log('b');
// good
if (user.isAuthenticated() &&
user.isInRole('admin') &&
user.hasAuthority('add-admin') ||
user.hasAuthority('delete-admin')) {
// Code
}
const result = number1 + number2 + number3 +
number4 + number5;
// bad
if (user.isAuthenticated()
&& user.isInRole('admin')
&& user.hasAuthority('add-admin')
|| user.hasAuthority('delete-admin')) {
// Code
}
const result = number1 + number2 + number3
+ number4 + number5;
// good
const obj = {
a: 1,
b: 2,
c: 3,
};
foo(
aVeryVeryLongArgument,
anotherVeryLongArgument,
callback
);
// bad
const obj = {
a: 1
, b: 2
, c: 3
};
foo(
aVeryVeryLongArgument
, anotherVeryLongArgument
, callback
);
// 仅为按逻辑换行的示例,不代表setStyle的最优实现
function setStyle(element, property, value) {
if (element == null) {
return;
}
element.style[property] = value;
}
// good
const { name: personName, email: personEmail } = person;
const {
name: personName,
email: personEmail,
sex: personSex,
age: personAge
} = person;
const person = { name: personName, email: personEmail };
const person = {
name: personName,
email: personEmail,
sex: personSex,
age: personAge,
};
// bad
const {name: personName, email: personEmail,
sex: personSex, age: personAge
} = person;
const person = {name: personName, email: personEmail,
sex: personSex, age: personAge};
// good
if (xxx) {
} else {
}
// bad
if (xxx) {
}
else {
}
const loadingModules = {};
function stringFormat(source) {
}
function hear(theBells) {
}
class Demo {
text = 'this demo';
appendTo() {
}
}
class TextNode( {
cloneData() {
}
}
const TargetState = {
READING: 1,
READED: 2,
APPLIED: 3,
READY_TO_GO: 4,
};
// good
function insertHTML(element, html) {
}
const httpRequest = new HTTPRequest();
// bad
function insertHtml(element, html) {
}
const httpRequest = new httpRequest();
// good
const age = 10;
export const age = 10;
// bad
const age = 10
export const age = 10
// good
function funcName() {
}
export function funcName() {
}
// bad
function funcName() {
};
export function funcName() {
};
// 如果是函数表达式,分号是不允许省略的。
const funcName = function () {
};
// good
class A {
}
// bad
class A {
};
// good
class Foo {
foo = 3;
bar() {
}
}
// bad
class Foo {
foo = 3
bar() {
};
}
// good
class Foo {
@log('INFO')
bar() {
}
@log('INFO');
['bar' + 2]() {
}
}
// bad
class Foo {
@log('INFO');
bar() {
}
@log('INFO')
['bar' + 2]() {
}
}
// good
const task = (function () {
// Code
return result;
})();
const func = function () {
};
// bad
const task = function () {
// Code
return result;
}();
const func = (function () {
});
// good
list.map(item => item * 2);
// good
const fetchName = async id => {
const user = await request(`users/${id}`);
return user.fullName;
};
// bad
list.map((item) => item * 2);
// bad
const fetchName = async (id) => {
const user = await request(`users/${id}`);
return user.fullName;
};
// good
list.map(item => item * 2);
const foo = () => (
condition
? returnValueA()
: returnValueB()
);
// bad
list.map(item => {
return item * 2;
});
// good
list.map(item => ({ name: item[0], email: item[1] }));
// good
if (condition) {
callFunc();
}
if (condition) {
return;
}
// bad
if (condition) callFunc();
if (condition) { callFunc(); }
if (condition) { return; }
if (condition) return;
if (condition)
callFunc();
callFunc();
// good
for (let i = 0; i < 10; i++) {
}
// bad
for (var i = 0; i < 10; i++) {
}
// good
const name = 'MyName';
// bad
name = 'MyName';
// good
const hangModules = [];
const missModules = [];
const visited = {};
// bad 一次声明多个变量
const hangModules = [],
missModules = [],
visited = {};
// bad 使用保留字作为变量名
const function = 'a';
// bad 将`undefined`赋值给变量
const a = undefined;
// bad 连续赋值
const a = b = c = 5;
// good
function kv2List(source) {
const list = [];
for (let key in source) {
if (source.hasOwnProperty(key)) {
const item = {
k: key,
v: source[key],
};
list.push(item);
}
}
const str = list.join('/');
return { list, str };
}
// bad
function kv2List(source) {
const list = [];
let key;
let item;
let str;
for (key in source) {
if (source.hasOwnProperty(key)) {
item = {
k: key,
v: source[key],
};
list.push(item);
}
}
str = list.join('/');
return { list, str };
}
// bad
const { documentElement: { firstElementChild: { nextSibling } } } = window;
// 下面交换变量的 demo 中,使用解构会牺牲一部分性能,但却获得了更简洁的代码,所以在非强性能场景下,我们推荐使用解构的方式。关于性能的影响,可以参考:这个链接
// good
[x, y] = [y, x];
// bad
let temp = x;
x = y;
y = temp;
// good
const len = myString.length;
// bad
const { length: len } = myString;
// good
const { first: firstName, last: lastName } = person;
const one = 1;
const two = 2;
// bad
const [ one, two, three ] = [ 1, 2, 3 ];
const { one, two } = { one: 1, two: 2 };
// good
let [one, two, ...anyOther] = myArray;
let other = myArray.slice(3);
// bad
let [,,, ...other] = myArray;
// good
if (age === 30) {
// ......
}
// bad
if (age == 30) {
// ......
}
// good
if (x == null) {
}
// bad
if (x === null || x === undefined) {
}
// 字符串为空
// good
if (!name) {
// ......
}
// bad
if (name === '') {
// ......
}
// 字符串非空
// good
if (name) {
// ......
}
// bad
if (name !== '') {
// ......
}
// 数组非空
// good
if (collection.length) {
// ......
}
// bad
if (collection.length > 0) {
// ......
}
// 布尔不成立
// good
if (!notTrue) {
// ......
}
// bad
if (notTrue === false) {
// ......
}
// null 或 undefined
// good
if (noValue == null) {
// ......
}
// bad
if (noValue === null
|| typeof noValue === 'undefined') {
// ......
}
// 不要使用嵌套的三元表达式
// bad
if (a ? b : c ? d : e) {
// ......
}
// good
if (!expressionA) {
return;
}
process(a);
if (!expressionB) {
return;
}
process(b);
if (expressionC) {
// do sth
} else {
// do sth
}
// bad
if (expresssionA) {
process(a);
if (expressionB) {
process(b);
if (expressionC) {
// do sth
} else {
// do sth
}
}
}
if (condition === '执行频率最高') {
// ...
} else if (condition === '执行频率中等') {
// ...
} else if (condition === '执行频率最低') {
// ...
}
switch (condition) {
case '执行频率最高':
// ...
break;
case '执行频率中等':
// ...
break;
case '执行频率最低':
// ...
break;
}
switch (typeof variable) {
case 'object':
// ......
break;
case 'number':
case 'boolean':
case 'string':
// ......
break;
}
// bad
const type = typeof variable;
if (type === 'object') {
// ......
} else if (type === 'number'
|| type === 'boolean'
|| type === 'string') {
// ......
}
// good
switch (input) {
case 1:
case 2:
prepareOneOrTwo();
// fall through
case 3:
handleOneTwoOrThree();
break;
default:
handleLargeNumber(input);
}
// good
function clicker() {
// ......
}
for (let i = 0, len = elements.length; i < len; i++) {
const element = elements[i];
addListener(element, 'click', clicker);
}
// bad
for (let i = 0, len = elements.length; i < len; i++) {
const element = elements[i];
addListener(element, 'click', function () {});
}
// good
const width = wrap.offsetWidth + 'px';
for (let i = 0, len = elements.length; i < len; i++) {
const element = elements[i];
element.style.width = width;
// ......
}
// bad
for (let i = 0, len = elements.length; i < len; i++) {
const element = elements[i];
element.style.width = wrap.offsetWidth + 'px';
// ......
}
// 正序遍历
for (let i = 0, len = elements.length; i < len; i++) {
const element = elements[i];
// ......
}
// 逆序遍历
let len = elements.length;
while (len--) {
const element = elements[len];
// ......
}
// string
typeof variable === 'string'
// number
typeof variable === 'number'
// boolean
typeof variable === 'boolean'
// Function
typeof variable === 'function'
// Object
typeof variable === 'object'
// RegExp
variable instanceof RegExp
// Array
Array.isArray(variable)
// null
variable === null
// null or undefined
variable == null
// undefined
typeof variable === 'undefined'
// good
const str = String(num);
// bad
const str = num + '';
// good
const number = Number(str);
// bad
const number = +str;
// good
const width = '200px';
parseInt(width, 10);
// bad
const width = '200px';
parseInt(width);
// good
const isRed = Boolean(red);
// bad
const isRed = !!red;
// good
const num = 3.14;
Math.ceil(num);
// bad
const num = 3.14;
parseInt(num, 10);
// good
const num1 = 0.5;
const num2 = 2.0;
const num3 = -0.7;
// bad
const num1 = .5;
const num2 = 2.;
const num3 = -.7;
const str = '我是一个字符串';
const html = '拼接HTML可以省去双引号转义';
// HTML 转义
const str = ''
+ htmlEncode(content) + '';
// HTML 转义
const str = '+ htmlEncode(value) + '">';
// URL 转义
const str = '+ htmlEncode(urlEncode(value)) + '">link';
// JavaScript字符串 转义 + HTML 转义
const str = '';
const str = `'name': ${name}`;
// good
const longString = 'This is a very long string that far exceeds the 80 '
+ 'column limit. It does not contain long stretches of spaces since '
+ 'the concatenated strings are cleaner.';
// bad
const longString = 'This is a very long string that far exceeds the 80 \
column limit. It unfortunately contains long stretches of spaces due \
to how the continued lines are indented.';
// good
const fullName = getFullName(getFirstName(), getLastName());
const s = `Hello ${fullName}`;
// bad
const s = `Hello ${getFullName(getFirstName(), getLastName())}`;
// good
const obj = {};
// bad
const obj = new Object();
// good
const info = {
name: 'someone',
age: 28,
'x-y': 20,
};
// bad
const info = {
'name': 'someone',
'age': 28,
'x-y': 20,
};
// good
const foo = {
name: 'someone',
age: 28,
};
const bar = { name: 'someone', age: 28 };
// bad
const foo = {
name: 'someone',
age: 28
};
const bar = { name: 'someone', age: 28, };
// 以下行为绝对禁止
String.prototype.trim = function () {
};
info.age;
info.more_info;
info['more-info'];
// good
const foo = {
z,
x: 1,
y: 2,
};
// bad
const foo = {
x: 1,
y: 2,
z: z,
};
const bar = {
x: 1,
y: 2,
z,
};
// good
const foo = {
bar(x, y) {
return x + y;
}
};
const foo = {
bar: hoc(function (x, y) {
return x + y;
})
};
// bad
const foo = {
bar: function (x, y) {
return x + y;
}
};
const foo = {
bar: (x, y) => x + y
};
// good
for (let key of Object.keys(foo)) {
const value = foo[key];
}
// good
for (const [key, value] of Object.entries(foo)) {
// ...
}
// good
const MY_KEY = 'bar';
const foo = {
[MY_KEY + 'Hash']: 123
};
// bad
const MY_KEY = 'bar';
const foo = {};
foo[MY_KEY + 'Hash'] = 123;
// good
console.log(Object.prototype.hasOwnProperty.call(object, key));
const has = Object.prototype.hasOwnProperty;
console.log(has.call(object, key));
// bad
console.log(object.hasOwnProperty(key));
// good
const obj = { ...oldObj };
// bad
const obj = Object.assign({}, oldObj);
// good
const arr = [];
// bad
const arr = new Array();
// good
const arr = [ ...oldArr ];
// bad
const arr = Array.from(oldArr);
// good
foo = [...foo, newValue];
bar = [...bar, ...newValues];
// bad
foo = foo.concat(newValue);
bar = bar.concat(newValues);
// good
const foo = [
'first value',
'second value',
];
const bar = [ 'first value', 'second value' ];
// bad
const foo = [
'first value',
'second value'
];
const bar = [ 'first value', 'second value', ];
const numbers = [1, 2, 3, 4, 5];
// 数组求和
// bad
let sum = 0;
for (let num of numbers) {
sum += num;
}
sum === 15;
// good
let sum = 0;
numbers.forEach(num => {
sum += num;
});
sum === 15;
// best 使用最恰当的方法
const sum = numbers.reduce((total, num) => total + num, 0);
sum === 15;
// 数组所有元素 +1
// bad
const increasedByOne = [];
for (let i = 0; i < numbers.length; i++) {
increasedByOne.push(numbers[i] + 1);
}
// good
const increasedByOne = [];
numbers.forEach((num) => {
increasedByOne.push(num + 1);
});
// best 使用最恰当的方法
const increasedByOne = numbers.map(num => num + 1);
// bad
function syncViewStateOnUserAction() {
if (x.checked) {
y.checked = true;
z.value = '';
} else {
y.checked = false;
}
if (a.value) {
warning.innerText = '';
submitButton.disabled = false;
} else {
warning.innerText = 'Please enter it';
submitButton.disabled = true;
}
}
// good 直接阅读该函数会难以明确其主线逻辑,因此下方是一种更合理的表达方式:
function syncViewStateOnUserAction() {
syncXStateToView();
checkAAvailability();
}
function syncXStateToView() {
y.checked = x.checked;
if (x.checked) {
z.value = '';
}
}
function checkAAvailability() {
if (a.value) {
clearWarnignForA();
} else {
displayWarningForAMissing();
}
}
// good
function doSomething(firstname, lastname, age) {
// …
}
function doSomething(
veryLongArgumentOne,
veryLongArgumentTwo,
veryLongArgumentThree,
veryLongArgumentFour) {
// …
}
function doSomething(person) {
// …
}
// bad
function doSomething(firstname, lastname, age, veryLongArgumentOne, veryLongArgumentTwo, veryLongArgumentThree, veryLongArgumentFour) {
// …
}
// good
function info (person) {
const thisInfo = {...person.info};
thisInfo.xx = 'info';
return thisInfo;
}
// bad
function info (person) {
const thisInfo = person.info;
thisInfo.xx = 'info';
return thisInfo;
}
// good
function foo(text = 'hello') {
}
// bad
function foo(text) {
text = (typeof text !== 'undefined') ? text : 'hello';
}
function foo(text) {
text = text || 'hello';
}
// good
function foo(...args) {
console.log(args.join(''));
}
// bad
function foo() {
console.log([].join.call(arguments));
}
// good
class TextNode {
constructor(value, engine) {
this.value = value;
this.engine = engine;
}
clone() {
return this;
}
}
// bad
function TextNode(value, engine) {
this.value = value;
this.engine = engine;
}
TextNode.prototype.clone = function () {
return this;
};
// good
class Rey extends Jedi {
constructor(...args) {
super(...args);
this.name = 'Rey';
}
}
// bad
class Jedi {
constructor() {}
getName() {
return this.name;
}
}
class Rey extends Jedi {
constructor(...args) {
super(...args);
}
}
// good
class TextNode extends Node {
constructor(value, engine) {
super(value);
this.engine = engine;
}
setNodeValue(value) {
super.setNodeValue(value);
this.textContent = value;
}
}
// bad
class TextNode extends Node {
constructor(value, engine) {
Node.apply(this, value);
this.engine = engine;
}
setNodeValue(value) {
Node.prototype.setNodeValue.call(this, value);
this.textContent = value;
}
}
class TextNode extends Node {
constructor(value, engine) {
super(value);
super.engine = engine;
}
}
// good
import util from './util';
export default function () {};
// bad
const util = require('./util');
module.exports = function () {};
// good
export function foo() {
}
// bad
function foo() {
}
export { foo };
// good
import { bar } from './bar';
function foo() {
import('./foo').then(foo => console.log(foo));
bar.work();
}
// bad
function foo() {
bar.work();
}
import { bar } from './bar';
// good
export default ComponentA;
// bad
const ComponentA = /* ... */;
const ComponentB = /* ... */;
export default {
ComponentA,
ComponentB
}
// good
exports.foo = function foo() {
};
// good
module.exports = function foo() {
};
// bad
exports = function foo() {
};