更多或详细请在原网址https://lin-123.github.io/javascript/中查看
避免使用symbol
类型
所有的赋值都用const
,避免使用var
,如果是需要重新赋值的变量,使用let
使用字面值创建对象
// bad
const item = new Object();
// good
const item = {};
当创建一个带有动态属性名的对象时,用计算后属性名
function getKey(k) {
return `a key named ${k}`;
}
// bad
const obj = {
id: 5,
name: 'San Francisco',
};
obj[getKey('enabled')] = true;
// good getKey('enabled')是动态属性名
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;
},
};
用属性值缩写
const lukeSkywalker = 'Luke Skywalker';
// bad
const obj = {
lukeSkywalker: lukeSkywalker,
};
// good
const obj = {
lukeSkywalker,
};
将你的所有缩写放在对象声明的开始
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,
};
只对那些无效的标示使用引号
// 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
。
对象浅拷贝时,更推荐使用扩展运算符就是…运算符],而不是[Object.assign。获取对象指定的几个属性时,用对象的rest解构运算符[也是…运算符]更好。
// 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 es6扩展运算符 ...
const original = { a: 1, b: 2 };
// 浅拷贝
const copy = { ...original, c: 3 }; // copy => { a: 1, b: 2, c: 3 }
// rest 赋值运算符
const { a, ...noA } = copy; // noA => { b: 2, c: 3 }
用Array#push
代替直接向数组中添加一个值
const someStack = [];
// bad
someStack[someStack.length] = 'abracadabra';
// good
someStack.push('abracadabra');
用 … 运算符而不是Array.from
来将一个可迭代的对象转换成数组。
const foo = document.querySelectorAll('.foo');
// good
const nodes = Array.from(foo);
// best
const nodes = [...foo];
用 Array.from
去将一个类数组对象转成一个数组。
const arrLike = { 0: 'foo', 1: 'bar', 2: 'baz', length: 3 };
// bad
const arr = Array.prototype.slice.call(arrLike);
// good
const arr = Array.from(arrLike);
用 Array.from
而不是 … 运算符去做map遍历。 因为这样可以避免创建一个临时数组。
// bad
const baz = [...foo].map(bar);
// good
const baz = Array.from(foo, bar);
在数组方法的回调函数中使用 return
语句。 如果函数体由一条返回一个表达式的语句组成, 并且这个表达式没有副作用, 这个时候可以忽略return
用对象的解构赋值来获取和使用对象某个或多个属性值
// 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}`;
}
多个返回值用对象的解构,而不是数组解构。
超过100个字符的字符串不应该用string串联成多行。
用字符串模板而不是字符串拼接来组织可编程字符串。
// 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(),他就是潘多拉盒子。
不要使用不必要的转义字符。
用命名函数表达式而不是函数声明。
//函数表达式: const func = function () {}
//函数声明: function func() {}
// bad
function foo() {
// ...
}
// bad
const foo = function () {
// ...
};
// good
// lexical name distinguished from the variable-referenced invocation(s)
// 函数表达式名和声明的函数名是不一样的
const short = function longUniqueMoreDescriptiveLexicalFoo() {
// ...
};
把立即执行函数包裹在圆括号里。
// immediately-invoked function expression (IIFE)
(function () {
console.log('Welcome to the Internet. Please follow me.');
}());
不要在非函数块(if
、while
等等)内声明函数。
不要用arguments
命名参数。他的优先级高于每个函数作用域自带的 arguments
对象, 这会导致函数自带的 arguments
值被覆盖
// bad
function foo(name, options, arguments) {
// ...
}
// good
function foo(name, options, args) {
// ...
}
用默认参数语法,把默认参数赋值放在最后。
不要用函数构造器创建函数。
// bad
var add = new Function('a', 'b', 'return a + b');
// still bad
var subtract = Function('a', 'b', 'return a - b');
不修改参数。
当你一定要用函数表达式(在回调函数里)的时候就用箭头表达式吧。
// 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
。否则,继续用大括号和 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}.`);
// good
[1, 2, 3].map((number) => {
const nextNumber = number + 1;
return `A string containing the ${nextNumber}.`;
});
// good
[1, 2, 3].map((number, index) => ({
[index]: number
}));
// 表达式有副作用就不要用隐式return
function foo(callback) {
const val = callback();
if (val === true) {
// Do something if callback returns true
}
}
let bool = false;
// bad
// 这种情况会return bool = true, 不好
foo(() => bool = true);
// good
foo(() => {
bool = true;
});
如果你的函数只有一个参数并且函数体没有大括号,就删除圆括号。否则,参数总是放在圆括号里。
// bad
[1, 2, 3].map((x) => x * x);
// good
[1, 2, 3].map(x => x * x);
// good
[1, 2, 3].map(number => (
`A long string with the ${number}. It’s so long that we don’t want it to take up space on the .map line!`
));
// bad
[1, 2, 3].map(x => {
const y = x + 1;
return x * y;
});
// good
[1, 2, 3].map((x) => {
const y = x + 1;
return x * y;
});
在隐式return
中强制约束函数体的位置, 就写在箭头后面。
// bad
(foo) =>
bar;
(foo) =>
(bar);
// good
(foo) => bar;
(foo) => (bar);
(foo) => (
bar
)
一个路径只 import 一次
import 放在其他所有语句之前
在import语句里不允许Webpack loader语法
// bad
import fooSass from 'css!sass!foo.scss';
import barCss from 'style!css!bar.css';
// good
import fooSass from 'foo.scss';
import barCss from 'bar.css';
不要用遍历器。用JavaScript
高级函数代替for-in
、 for-of
。用数组的这些迭代方法: map() / every() / filter() / find() / findIndex() / reduce() / some() / ...
, 用对象的这些方法 Object.keys() / Object.values() / Object.entries()
去产生一个数组, 这样你就能去遍历对象了
访问属性时使用点符号,当获取的属性是变量时用方括号[]取
在赋值的时候避免在 =
前/后换行
用 ===
和 !==
而不是 ==
和 !=
比较布尔值用缩写,而字符串和数字要明确比较对象
三元表达式不应该嵌套,通常是单行表达式。
避免不需要的三元表达式
// bad
const foo = a ? a : b;
const bar = c ? true : false;
const baz = c ? false : true;
// good
const foo = a || b;
const bar = !!c;
const baz = !c;
用圆括号来混合这些操作符。 只有当标准的算术运算符(+, -, *, & /)
, 并且它们的优先级显而易见时,可以不用圆括号括起来。
// bad
const foo = a && b < 0 || c > 0 || d + 1 === 0;
// bad
const bar = a ** b - 5 % d;
// bad
// 别人会陷入(a || b) && c 的迷惑中
if (a || b && c) {
return 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;
多行注释用 /** … */
单行注释用//,将单行注释放在被注释区域上面。如果注释不是在第一行,那么注释前面就空一行
所有注释开头空一个,方便阅读。
// 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’或TODO’前缀, 这有助于其他开发人员快速理解你指出的需要重新访问的问题, 或者您建议需要实现的问题的解决方案。 这些不同于常规注释,因为它们是可操作的。 动作是FIXME: - 需要计算出来或TODO: - 需要实现。
class Calculator extends Abacus {
constructor() {
super();
// FIXME: shouldn't use a global here
total = 0;
}
}
class Calculator extends Abacus {
constructor() {
super();
// TODO: total should be configurable by an options param
this.total = 0;
}
}
在控制语句(if, while 等)的圆括号前空一格。在函数调用和定义时,参数列表和函数名之间不空格。
// bad
if(isJedi) {
fight ();
}
// good
if (isJedi) {
fight();
}
// bad
function fight () {
console.log ('Swooosh!');
}
// good
function fight() {
console.log('Swooosh!');
}
在一个代码块后下一条语句前空一行。
不要用空白行填充块。
不要在代码之间使用多个空白行填充。
圆括号里不要加空格。
// bad
function bar( foo ) {
return foo;
}
// good
function bar(foo) {
return foo;
}
// bad
if ( foo ) {
console.log(foo);
}
// good
if (foo) {
console.log(foo);
}
方括号里不要加空格。
// bad
const foo = [ 1, 2, 3 ];
console.log(foo[ 0 ]);
// good, 逗号分隔符还是要空格的
const foo = [1, 2, 3];
console.log(foo[0]);
花括号里加空格。作为语句的花括号内也要加空格 —— {
后和 }
前都需要空格。
// bad
const foo = {clark: 'kent'};
// good
const foo = { clark: 'kent' };
,
前不要空格, ,
后需要空格。
在对象的字面量属性中, key
value
之间要有空格。
用小驼峰式命名你的对象、函数、实例。用大驼峰式命名类。
不要用前置或后置下划线。
不要保存引用this
, 用箭头函数或函数绑定——Function#bind
// 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);
};
}
当你export-default
一个函数时,函数名用小驼峰,文件名需要和函数名一致。
当你export
一个结构体/类/单例/函数库/对象 时用大驼峰。
简称和缩写应该全部大写或全部小写。
你可以用全大写字母设置静态变量,他需要满足三个条件
- 导出变量 是
const
定义的 - 保证不能被改变 这个变量是可信的
- 他的子属性都是不能被改变的
不要使用JavaScript
的getters/setters
,因为他们会产生副作用,并且难以测试、维护和理解。相反的,你可以用getVal()
和setVal('hello')
去创造你自己的accessor
函数
用Number.isNaN
代替全局的isNaN
// bad
isNaN('1.2'); // false
isNaN('1.2.3'); // true
// good
Number.isNaN('1.2.3'); // false
Number.isNaN(Number('1.2.3')); // true
用 Number.isFinite
代替 isFinite
// bad
isFinite('2e3'); // true
// good
Number.isFinite('2e3'); // false
Number.isFinite(parseInt('2e3', 10)); // true