Best Practise
数组如下方法的 callback 中强制要求 return 声明
数组有很多用于 filtering/mapping/folding 的方法,如果在这些方法的 callback 函数中没有 return,通常会导致程序出错
Array.from
Array.prototype.every
Array.prototype.filter
Array.prototype.find
Array.prototype.findIndex
Array.prototype.map
Array.prototype.reduce
Array.prototype.reduceRight
Array.prototype.some
Array.prototype.sort
// Bad
var indexMap = myArray.reduce(function(memo, item, index) {
memo[item] = index;
}, {});
var foo = Array.from(nodes, function(node) {
if (node.tagName === "DIV") {
return true;
}
});
var bar = foo.filter(function(x) {
if (x) {
return true;
} else {
return;
}
});
// Good
var indexMap = myArray.reduce(function(memo, item, index) {
memo[item] = index;
return memo;
}, {});
var foo = Array.from(nodes, function(node) {
if (node.tagName === "DIV") {
return true;
}
return false;
});
var bar = foo.map(node => node.getAttribute("id"));
var 声明的变量,避免在声明其的块级作用域外部使用
// Bad
function doIf() {
if (true) {
var build = true;
}
console.log(build);
}
function doIfElse() {
if (true) {
var build = true;
} else {
var build = false;
}
}
function doTryCatch() {
try {
var build = 1;
} catch (e) {
var f = build;
}
}
// Good
function doIf() {
var build;
if (true) {
build = true;
}
console.log(build);
}
function doIfElse() {
var build;
if (true) {
build = true;
} else {
build = false;
}
}
function doTryCatch() {
var build;
var f;
try {
build = 1;
} catch (e) {
f = build;
}
}
花括号使用规约
允许无括号的单行 if、else if、else、for、while、do,其他的表达式强制使用花括号
// Bad
if (foo)
doSomething();
else
doSomethingElse();
if (foo) foo(
bar,
baz);
// Good
if (foo) foo++; else doSomething();
if (foo) foo++;
else if (bar) baz()
else doSomething();
do something();
while (foo);
while (foo
&& bar) baz();
if (foo) {
foo++;
}
if (foo) { foo++; }
while (true) {
doSomething();
doSomethingElse();
}
Switch 表达式中强制要求 default 声明
// Bad
switch (a) {
case 1:
/* code */
break;
}
// Good
switch (a) {
case 1:
/* code */
break;
default:
/* code */
break;
}
switch (a) {
case 1:
/* code */
break;
// no default
}
尽可能使用 . 获取属性
// Bad
var x = foo["bar"];
// Good
var x = foo.bar;
var x = foo[bar]; // Property name is a variable, square-bracket notation required
var x = foo['class']; // 保留的关键字
使用 === 或 !== 取代 == 或 !=
// Bad
a == b
foo == true
bananas != 1
value == undefined
typeof foo == 'undefined'
'hello' != 'world'
0 == 0
true == true
foo == null
// Good
a === b
foo === true
bananas !== 1
value === undefined
typeof foo === 'undefined'
'hello' !== 'world'
0 === 0
true === true
foo === null
禁止使用 alert
// Bad
alert("here!");
confirm("Are you sure?");
prompt("What's your name?", "John Doe");
// Good
customAlert("Something happened!");
customConfirm("Are you sure?");
customPrompt("Who are you?");
function foo() {
var alert = myCustomLib.customAlert;
alert();
}
禁止使用 caller/callee
// Bad
function foo(n) {
if (n <= 0) {
return;
}
arguments.callee(n - 1);
}
[1,2,3,4,5].map(function(n) {
return !(n > 1) ? 1 : arguments.callee(n - 1) * n;
});
// Good
function foo(n) {
if (n <= 0) {
return;
}
foo(n - 1);
}
[1,2,3,4,5].map(function factorial(n) {
return !(n > 1) ? 1 : factorial(n - 1) * n;
});
Switch case/default 中禁止在非块级作用域中声明
声明语法包括:let、const、function、class,不允许在 case/default 中使用,除非 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;
}
default: {
class C {}
}
}
else 表达式之前禁止 return
// Bad
function foo() {
if (x) {
return y;
} else {
return z;
}
}
function foo() {
if (x) {
return y;
} else if (z) {
return w;
} else {
return t;
}
}
function foo() {
if (x) {
return y;
} else {
var t = "foo";
}
return t;
}
// Two warnings for nested occurrences
function foo() {
if (x) {
if (y) {
return y;
} else {
return x;
}
} else {
return z;
}
}
// Good
function foo() {
if (x) {
return y;
}
return z;
}
function foo() {
if (x) {
return y;
} else if (z) {
var t = "foo";
} else {
return w;
}
}
function foo() {
if (x) {
if (z) {
return y;
}
} else {
return z;
}
}
关于空函数
以下语法式允许的:
- arrowFunctions
const foo = () => {};
- functions
function foo() {}
const foo = function() {};
const obj = {
foo: function() {}
};
- methods
const obj = {
foo() {}
};
class A {
foo() {}
static foo() {}
}
以下语法是不允许的:
- generatorFunctions
function* foo() {}
const foo = function*() {};
- generaotrMethods
const obj = {
foo: function*() {},
*foo() {},
};
- getters/setters
const obj = {
get foo() {},
set foo(value) {},
};
- constructors
class A {
construtor() {}
}
- mixed
const obj = {
bar: 123,
foo: () => this.bar,
*foo() {},
};
禁止无意义的解构赋值
const {} = foo;
const [] = foo;
const {a: {}} = foo;
const {a: []} = foo;
function foo({}) {}
function foo([]) {}
function foo({a: {}}) {}
function foo({a: []}) {}
禁止使用 eval 表达式
eval 表达式存在安全隐患,也会让应用变得容易受攻击
禁止直接修改内建对象的 prototype 属性
// Bad
Object.prototype.a = "a";
Object.defineProperty(Array.prototype, "times", { value: 999 });
禁止在不使用 this 的情况下使用 bind
bind 方法用于改变函数的 this 对象,如果使用了 bind 方法,但是在函数中又没有使用 this,则认定为无效的 bind
// Bad
var x = function () {
foo();
}.bind(bar);
禁止无嵌套循环结构下的 label 标识位
// Bad
A: while (a) {
break A;
}
Switch case 中使用 break/throw 等中断循环结构
// Bad
switch(foo) {
case 1:
doSomething();
case 2:
doSomething();
}
// Good
switch(foo) {
case 1:
doSomething();
break;
case 2:
doSomething();
}
switch(foo) {
case 1:
doSomething();
throw new Error("Boo!");
case 2:
doSomething();
}
浮点数表示
以下为错误的浮点数表示方式:
var num = .5;
var num = 2.;
var num = -.7;
以下为正确的浮点数表示方式:
var num = 0.5;
var num = 2.0;
var num = -0.7;
使用函数作为 setTimeout、setInterval、execScript 等语句的参数,而不是使用字符串
// Bad
setTimeout("alert('Hi!');", 100);
setInterval("alert('Hi!');", 100);
execScript("alert('Hi!')");
window.setTimeout("count = 5", 10);
window.setInterval("foo = bar", 10);
// Good
setTimeout(function() {
alert("Hi!");
}, 100);
setInterval(function() {
alert("Hi!");
}, 100);
禁止使用 label 结合 break、continue 来控制多层循环
禁止使用非必要的块级作用域
// Bad
{}
if (foo) {
bar();
{
baz();
}
}
function bar() {
{
baz();
}
}
{
function foo() {}
}
{
aLabel: {
}
}
// Good
while (foo) {
bar();
}
if (foo) {
if (bar) {
baz();
}
}
function bar() {
baz();
}
{
let x = 1;
}
{
const y = 1;
}
{
class Foo {}
}
aLabel: {
}
禁止在循环体中声明函数
循环体中声明的函数形成闭包,容易造成程序运行结果超出预期
// Bad
for (var i=10; i; i--) {
(function() { return i; })();
}
while(i) {
var a = function() { return i; };
a();
}
do {
function a() { return i; };
a();
} while (i);
let foo = 0;
for (let i=10; i; i--) {
// Bad, function is referencing block scoped variable in the outer scope.
var a = function() { return foo; };
a();
}
// Good
var a = function() {};
for (var i=10; i; i--) {
a();
}
for (var i=10; i; i--) {
a();
}
for (var i=10; i; i--) {
var a = function() {}; // OK, no references to variables in the outer scopes.
a();
}
for (let i=10; i; i--) {
var a = function() { return i; }; // OK, all references are referring to block scoped variables in the loop.
a();
}
var foo = 100;
for (let i=10; i; i--) {
var a = function() { return foo; }; // OK, all references are referring to never modified variables.
a();
}
禁止多余的空格
// Bad
var a = 1;
if(foo === "bar") {}
a << b
var arr = [1, 2];
a ? b: c
// Good
var a = 1;
if(foo === "bar") {}
a << b
var arr = [1, 2];
a ? b: c
禁止多行形式的字符串
// Bad
var x = "Line 1 \
Line 2";
// Good
var x = "Line 1\n" +
"Line 2";
禁止重新声明内置对象
// Bad
Object = null
undefined = 1
禁止使用函数构造器 new Function
// Bad
var x = new Function("a", "b", "return a + b");
禁止使用构造器的方式创建原始类型:string、number、boolean
使用构造器的方式创建原始数据类型,会造成使用困扰,如下示例:
var stringObject = new String("Hello world");
console.log(typeof stringObject); // "object"
var text = "Hello world";
console.log(typeof text); // "string"
var booleanObject = new Boolean(false);
if (booleanObject) { // all objects are truthy!
console.log("This executes");
}
因此,禁止使用构造器的方式创建以上原始数据类型
禁止使用八进制字面量
八进制的方式表示的字面量,由于以 0 开头,容易造成 Javascript 运行混乱,不建议使用八进制字面量
// Bad
var num = 071;
var result = 5 + 07;
// Good
var num = "071";
禁止使用字符串的八进制转义序列,应该使用 Unicode 转义序列替代
// Bad
var foo = "Copyright \251";
// Good
var foo = "Copyright \u00A9"; // unicode
禁止使用 proto
ECMAScript 3.1 标准中已经废弃了该属性,请使用 getPrototypeOf() 方法替代
// Bad
var a = obj.__proto__;
var a = obj["__proto__"];
// Good
var a = Object.getPrototypeOf(obj);
禁止重复声明变量
// Bad
var a = 3;
var a = 10;
// Good
var a = 3;
a = 10;
禁止在 return 表达式中使用赋值运算符
// Bad
function doSomething() {
return foo = bar + 2;
}
function doSomething() {
return foo += 2;
}
// Good
function doSomething() {
return foo == bar + 2;
}
function doSomething() {
return foo === bar + 2;
}
function doSomething() {
return (foo = bar + 2);
}
禁止使用 javascript: 表达式
// Bad
location.href = "javascript:void(0)";
禁止自赋值
// Bad
foo = foo;
[a, b] = [a, b];
[a, ...b] = [x, ...b];
({a, b} = {a, x});
// Good
foo = bar;
[a, b] = [b, a];
// This pattern is warned by the `no-use-before-define` rule.
let foo = foo;
// The default values have an effect.
[foo = 1] = [foo];
禁止自比较
// Bad
var x = 10;
if (x === x) {
x = 20;
}
禁止使用逗号操作符
// Bad
foo = doSomething(), val;
0, eval("doSomething();");
do {} while (doSomething(), !!test);
for (; doSomething(), !!test; );
if (doSomething(), !!test);
switch (val = foo(), val) {}
while (val = foo(), val < 42);
with (doSomething(), val) {}
// Good
foo = (doSomething(), val);
(0, eval)("doSomething();");
do {} while ((doSomething(), !!test));
for (i = 0, j = 10; i < j; i++, j--);
if ((doSomething(), !!test));
switch ((val = foo(), val)) {}
while ((val = foo(), val < 42));
禁止使用未被使用的 label
// Bad
A: var foo = 0;
B: {
foo();
}
C:
for (let i = 0; i < 10; ++i) {
foo();
}
// Good
A: {
if (foo()) {
break A;
}
bar();
}
B:
for (let i = 0; i < 10; ++i) {
if (foo()) {
break B;
}
bar();
}
禁止不必要的字符串链接操作
// Bad
var a = `some` + `string`;
var a = '1' + '0';
var a = '1' + `0`;
var a = `1` + '0';
var a = `1` + `0`;
// Good
var c = a + b;
var c = '1' + a;
var a = 1 + '1';
var c = 1 - 2;
// when the string concatenation is multiline
var c = "foo" +
"bar";
禁止使用 with 表达式
// Bad
with (point) {
r = Math.sqrt(x * x + y * y); // is r a member of point?
}
// Good
const r = ({x, y}) => Math.sqrt(x * x + y * y);
禁止 Yoda 表达式
// Bad
if ("red" === color) {
// ...
}
// Good
if (color === "red") {
// ...
}
严格模式
只允许全局的方式声明严格模式,即在一个脚本最上面添加:
"use strict";
function foo() {}
变量
禁止使用 delete 操作符删除变量
delete 操作符只建议在删除对象属性的时候使用
// Bad
var x;
delete x;
禁止使用跟同作用域下的变量名一样的 label 名
// Bad
var x = foo;
function bar() {
x:
for (;;) {
break x;
}
}
// Good
function foo() {
var q = t;
}
function bar() {
q:
for(;;) {
break q;
}
}
禁止将受限制的关键字作为变量名
受限制的关键字,如 NaN、Infinity、undefined、eval、arguments 等
// Bad
function NaN(){}
!function(Infinity){};
var undefined;
try {} catch(eval){}
// Good
var Object;
function f(a, b){}
禁止使用未声明的变量
// Bad
var a = someFunction();
b = 10;
// Good
var a = someFunction();
var b;
b = 10;
禁止声明未使用的变量
禁止先使用、后声明的方式使用变量
Error
尾随逗号
建议在多行情况下,永远在最后一个元素或属性后面添加逗号;单行情况下不需要在最后一行添加逗号;
// Bad
var foo = {
bar: "baz",
qux: "quux"
};
var foo = { bar: "baz", qux: "quux", };
var arr = [1,2,];
var arr = [1,
2,];
var arr = [
1,
2
];
foo({
bar: "baz",
qux: "quux"
});
// Good
var foo = {
bar: "baz",
qux: "quux",
};
var foo = {bar: "baz", qux: "quux"};
var arr = [1,2];
var arr = [1,
2];
var arr = [
1,
2,
];
foo({
bar: "baz",
qux: "quux",
});
禁止在判断条件中使用赋值语句
如果条件表达式中需要使用赋值语句,请使用 () 将赋值语句包裹起来
// Bad
function setHeight(someNode) {
do {
someNode.height = "100px";
} while (someNode = someNode.parentNode);
}
// Good
function setHeight(someNode) {
do {
someNode.height = "100px";
} while ((someNode = someNode.parentNode));
}
禁止在判断条件中使用常量表达式
// Bad
if (false) {
doSomethingUnfinished();
}
if (void x) {
doSomethingUnfinished();
}
for (;-2;) {
doSomethingForever();
}
while (typeof x) {
doSomethingForever();
}
do {
doSomethingForever();
} while (x = -1);
var result = 0 ? a : b;
// Good
if (x === 0) {
doSomething();
}
for (;;) {
doSomethingForever();
}
while (typeof x === "undefined") {
doSomething();
}
do {
doSomething();
} while (x);
var result = x !== 0 ? a : b;
线上代码禁止使用 debugger
禁止在函数形参中重复声明变量
// Bad
function foo(a, b, a) {
console.log("value of the second a:", a);
}
var bar = function (a, b, a) {
console.log("value of the second a:", a);
};
// Good
function foo(a, b, c) {
console.log(a, b, c);
}
var bar = function (a, b, c) {
console.log(a, b, c);
};
禁止在对象字面量中添加相同的 key
// Bad
var foo = {
bar: "baz",
bar: "qux"
};
var foo = {
"bar": "baz",
bar: "qux"
};
var foo = {
0x1: "baz",
1: "qux"
};
// Good
var foo = {
bar: "baz",
quxx: "qux"
};
禁止存在相同的 case 表达式
// Bad
var a = 1,
one = 1;
switch (a) {
case 1:
break;
case 2:
break;
case 1: // duplicate test expression
break;
default:
break;
}
switch (a) {
case one:
break;
case 2:
break;
case one: // duplicate test expression
break;
default:
break;
}
switch (a) {
case "1":
break;
case "2":
break;
case "1": // duplicate test expression
break;
default:
break;
}
// Good
var a = 1,
one = 1;
switch (a) {
case 1:
break;
case 2:
break;
case 3:
break;
default:
break;
}
switch (a) {
case one:
break;
case 2:
break;
case 3:
break;
default:
break;
}
switch (a) {
case "1":
break;
case "2":
break;
case "3":
break;
default:
break;
}
禁止空快语句
// Bad
if (foo) {
}
while (foo) {
}
switch(foo) {
}
try {
doSomething();
} catch(ex) {
} finally {
}
// Good
if (foo) {
// empty
}
while (foo) {
/* empty */
}
try {
doSomething();
} catch (ex) {
// continue regardless of error
}
try {
doSomething();
} finally {
/* continue regardless of error */
}
正则表达式中禁止存在空的字符类
// Bad
/^abc[]/.test("abcdefg"); // false
"abcdefg".match(/^abc[]/); // null
// Good
/^abc/.test("abcdefg"); // true
"abcdefg".match(/^abc/); // ["abc"]
/^abc[a-z]/.test("abcdefg"); // true
"abcdefg".match(/^abc[a-z]/); // ["abcd"]
禁止在 catch 中重新声明异常形参
// Bad
try {
// code
} catch (e) {
e = 10;
}
// Good
try {
// code
} catch (e) {
var foo = 10;
}
禁止不必要的 boolean 类型转换
// Bad
var foo = !!!bar;
var foo = !!bar ? baz : bat;
var foo = Boolean(!!bar);
var foo = new Boolean(!!bar);
if (!!foo) {
// ...
}
if (Boolean(foo)) {
// ...
}
while (!!foo) {
// ...
}
do {
// ...
} while (Boolean(foo));
for (; !!foo; ) {
// ...
}
// Good
var foo = !!bar;
var foo = Boolean(bar);
function foo() {
return !!bar;
}
var foo = bar ? !!baz : !!bat;
禁止使用不必要的括号
// Bad
a = (b * c);
(a * b) + c;
typeof (a);
(function(){} ? a() : b());
// Good
(0).toString();
({}.toString.call());
(function(){}) ? a() : b();
(/^a$/).test(x);
禁止使用不必要的分号
// Bad
var x = 5;;
function foo() {
// code
};
// Good
var x = 5;
var foo = function() {
// code
};
禁止给声明好的函数重新赋值
// Bad
function foo() {}
foo = bar;
function foo() {
foo = bar;
}
// Good
var foo = function () {}
foo = bar;
function foo(foo) { // `foo` is shadowed.
foo = bar;
}
function foo() {
var foo = bar; // `foo` is shadowed.
}
禁止在嵌套的块级作用域中声明函数
// Bad
if (test) {
function doSomething() { }
}
function doSomethingElse() {
if (test) {
function doAnotherThing() { }
}
}
// Good
function doSomething() { }
function doSomethingElse() {
function doAnotherThing() { }
}
if (test) {
asyncCall(id, function (err, data) { });
}
var fn;
if (test) {
fn = function fnExpression() { };
}
禁止在正则表达式中存在非法的表达式
// Bad
RegExp('[')
RegExp('.', 'z')
new RegExp('\\')
// Good
RegExp('.')
new RegExp
this.RegExp('[')
禁止存在不规则的空白符
由于操作失误引入的不规则空白符,由于无法通过肉眼觉察,很容易引起程序运行出错
// Bad
function thing() /*<NBSP>*/{
return 'test';
}
function thing( /*<NBSP>*/){
return 'test';
}
function thing /*<NBSP>*/(){
return 'test';
}
function thing/*<MVS>*/(){
return 'test';
}
function thing() {
return 'test'; /*<ENSP>*/
}
function thing() {
return 'test'; /*<NBSP>*/
}
function thing() {
// Description <NBSP>: some descriptive text
}
/*
Description <NBSP>: some descriptive text
*/
function thing() {
return / <NBSP>regexp/;
}
/*eslint-env es6*/
function thing() {
return `template <NBSP>string`;
}
// Good
function thing() {
return ' <NBSP>thing';
}
function thing() {
return '<ZWSP>thing';
}
function thing() {
return 'th <NBSP>ing';
}
禁止在判断条件中的左操作符中做取反操作
// Bad
if(!key in object) {
// operator precedence makes it equivalent to (!key) in object
// and type conversion makes it equivalent to (key ? "false" : "true") in object
}
// Good
if(!(key in object)) {
// key is not in object
}
if(('' + !key) in object) {
// make operator precedence and type conversion explicit
// in a rare situation when that is the intended meaning
}
禁止用函数的方式调用全局对象
// Bad
var math = Math();
var json = JSON();
// Good
function area(r) {
return Math.PI * r * r;
}
var object = JSON.parse("{}");
禁止在正则表达式中存在多个空格
// Bad
var re = /foo bar/;
var re = new RegExp("foo bar");
// Good
var re = /foo {3}bar/;
var re = new RegExp("foo {3}bar");
禁止在数组中使用空元素
// Bad
var items = [,];
var colors = [ "red",, "blue" ];
// Good
var items = [];
var items = new Array(23);
// trailing comma (after the last element) is not a problem
var colors = [ "red", "blue", ];
禁止在 return、throw、continue、break 之后插入没有机会运行的代码
// Bad
function foo() {
return true;
console.log("done");
}
function bar() {
throw new Error("Oops!");
console.log("done");
}
while(value) {
break;
console.log("done");
}
throw new Error("Oops!");
console.log("done");
function baz() {
if (Math.random() < 0.5) {
return;
} else {
throw new Error();
}
console.log("done");
}
for (;;) {}
console.log("done");
// Good
function foo() {
return bar();
function bar() {
return 1;
}
}
function bar() {
return x;
var x;
}
switch (foo) {
case 1:
break;
var x;
}
禁止在 finally 中存在流程控制语句
finally 一般作为 try catch 之后执行的一段代码,不应该在 finally 中插入干扰 try catch 流程的代码,比如:return、throw、break、continue 等
// Bad
let foo = function() {
try {
return 1;
} catch(err) {
return 2;
} finally {
return 3;
}
};
let foo = function() {
try {
return 1;
} catch(err) {
return 2;
} finally {
throw new Error;
}
};
// Good
let foo = function() {
try {
return 1;
} catch(err) {
return 2;
} finally {
console.log("hola!");
}
};
let foo = function() {
try {
return 1;
} catch(err) {
return 2;
} finally {
let a = function() {
return "hola!";
}
}
};
let foo = function(a) {
try {
return 1;
} catch(err) {
return 2;
} finally {
switch(a) {
case 1: {
console.log("hola!")
break;
}
}
}
};
请使用 isNaN() 方法来检查一个值是否是 NaN
// Bad
if (foo == NaN) {
// ...
}
if (foo != NaN) {
// ...
}
// Good
if (isNaN(foo)) {
// ...
}
if (!isNaN(foo)) {
// ...
}
网友评论