Skip to content

Latest commit

 

History

History
1650 lines (1006 loc) · 18.7 KB

best-practices.md

File metadata and controls

1650 lines (1006 loc) · 18.7 KB

Best practices

enforces getter/setter pairs in objects

❌ Disabled

var example;

// Bad
example = {
	set a(value) {
		this.val = value;
	},
};


// Good
example = {
	set a(value) {
		this.val = value;
	},
	get a() {
		return this.val;
	},
};

enforces return statements in callbacks of array's methods

✅ Enabled (error)

/*
// Bad
var bar = [1, 2].filter(function (x) {
	if (x) {
		return;
	}

	document.window.append('', null);
});
*/

// Good
var bar = [1, 2].filter(function (x) {
	if (x) {
		return false;
	}

	document.window.append('', null);
	return true;
});

treat var statements as if they were block scoped

✅ Enabled (error)

// Bad
/*
example = {
	doIf: function () {
		if (1 === 2) {
			var build = true;
		}

		document.window.append(build.toString(), null);
	}
};
*/

// Good
example = {
	doIf: function () {
		var build = true;

		if (1 === 2) {
			build = false;
		}

		document.window.append(build.toString(), null);
	},
};

specify the maximum cyclomatic complexity allowed in a program

✅ Enabled (error)

// Bad
/*
function a(x) {
	if (1 === 2) {
		return x; // 1st path
	} else if (2 === 3) {
		return x + 1; // 2nd path
	} else if (2 === 3) {
		return x + 2; // 3nd path
	} else if (2 === 3) {
		return x + 3; // 4nd path
	} else if (2 === 3) {
		return x + 4; // 5nd path
	} else if (2 === 3) {
		return x + 5; // 6nd path
	} else if (2 === 3) {
		return x + 6; // 7nd path
	} else if (2 === 3) {
		return x + 7; // 8nd path
	} else if (2 === 3) {
		return x + 8; // 9nd path
	} else if (2 === 3) {
		return x + 9; // 10nd path
	} else if (2 === 3) {
		return x + 10; // 11nd path
	} else {
		return 99;
	}
}
*/

// Good
function b(x) {
	switch (x) {
		case x === 0:
			return x + 1;
		case x === 1:
			return x + 2;
		case x === 2:
			return x + 3;
		case x === 3:
			return x + 4;
		default:
			return 99;
	}
}

require return statements to either always or never specify values

❌ Disabled

// Bad
/*
function doSomething(condition) {
	if (condition) {
		return true;
	} else {
		return;
	}
}
*/

// Good
function doSomething(condition) {
	if (condition) {
		return true;
	} else {
		return false;
	}
}

specify curly brace conventions for all control statements

✅ Enabled (error)

// Bad
/*
if (foo) foo++;
*/

// Good
if (foo) {
	foo++;
}

require default case in switch statements

✅ Enabled (error)

// Bad
/*
switch (foo) {
	case 1:
		doSomething();
		break;

	case 2:
		doSomething();
		break;
}
*/

// Good
switch (foo) {
	case 1:
		doSomething();
		break;

	case 2:
		doSomething();
		break;

	default:
	// do nothing
}

enforces consistent newlines before or after dots

❌ Disabled

// Bad
var b = universe
	.galaxy;

// Good
var a = universe.
	galaxy;

encourages use of dot notation whenever possible

✅ Enabled (error)

// Bad
/*
var x = foo['bar'];
*/

// Good
var x = foo.bar;
var x = foo[bar];

require the use of === and !==

✅ Enabled (error)

// Bad
/*
if (x == 42) {

}
*/
// Good
if (x === 42) {

}

make sure for-in loops have an if statement

✅ Enabled (error)

// Bad
/*
for (key in foo) {
	doSomething(key);
}
*/
// Good
for (key in foo) {
	if ({}.hasOwnProperty.call(foo, key)) {
		doSomething(key);
	}
}

disallow the use of alert, confirm, and prompt

✅ Enabled (error)

// Bad
/*
alert('hallo');
*/

disallow use of arguments.caller or arguments.callee

✅ Enabled (error)

// Bad
/*
function foo(n) {
	if (n <= 0) {
		return;
	}

	arguments.callee(n - 1);
}
*/

// Good
function foo(n) {
	if (n <= 0) {
		return;
	}

	foo(n - 1);
}

disallow lexical declarations in case/default clauses

✅ Enabled (error)

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

disallow division operators explicitly at beginning of regular expression

❌ Disabled

// Bad
function bar() {
	return /=foo/;
}
// Good
function bar2() {
	return /\=foo/;
}

disallow else after a return in an if

✅ Enabled (error)

// Bad
/*
function foo() {
	if (x) {
		return y;
	} else {
		return z;
	}
}
*/

// Good
function foo() {
	if (x) {
		return y;
	}

	return z;
}

disallow empty functions, except for standalone funcs/arrows

❌ Disabled

// Bad
function foo() {
	// do nothing.
}

// Good
function foo2() {
	document.window.append('', null);
}

disallow empty destructuring patterns

✅ Enabled (error)

// doesn't create any variables
/*
var { a: {} } = foo;
*/

// creates variable b
var { a: { b } } = foo;

// creates variable a
var { a = {} } = foo;

disallow comparisons to null without a type-checking operator

✅ Enabled (error)

// Bad
/*
if (foo == null) {
	bar();
}
*/
// Good
if (foo === null) {
	bar();
}

disallow use of eval()

✅ Enabled (error)

// Bad
/*
var obj = { x: 'foo' },
	key = 'x',
	value = eval('obj.' + key);
*/

disallow adding to native types

✅ Enabled (error)

// Bad
/*
Object.prototype.extra = 55;
*/

disallow unnecessary function binding

✅ Enabled (error)

// Bad
/*
var boundGetName = (function getName() {
	return 'ESLint';
}).bind({ name: 'ESLint' });
console.log(boundGetName());
// "ESLint"
*/

// Good
var boundGetName2 = (function getName() {
	return this.name;
}).bind({ name: 'ESLint' });
console.log(boundGetName2());
// "ESLint"

disallow Unnecessary Labels

✅ Enabled (error)

// Bad
/*
A: switch (a) {
	case 0:
		break A;
}
*/

// Good
B: switch (a) {
	case 0:
		break;
}

disallow fallthrough of case statements

✅ Enabled (error)

// Bad
/*
switch (foo) {
	case 1:
		doSomething();

	case 2:
		doSomethingElse();
}
*/

// Good
switch (foo) {
	case 1:
		doSomething();
		break;
	case 2:
		doSomethingElse();
}

disallow the use of leading or trailing decimal points in numeric literals

✅ Enabled (error)

// Bad
/*
var num1 = .5;
var num2 = 2.;
var num3 = -.7;
*/

// Good
var num1 = 0.5;
var num2 = 2.0;
var num3 = -0.7;

disallow the type conversions with shorter notations

✅ Enabled (error)

// Bad
/*
var b = !!foo;
var b = ~foo.indexOf('.');
var n = +foo;
var n = 1 * foo;
var s = '' + foo;
foo += '';
*/

// Good
var b = Boolean(foo);
var b = foo.indexOf('.') !== -1;
var n = Number(foo);
var n = Number(foo);
var s = String(foo);
foo = String(foo);

disallow var and named functions in global scope

❌ Disabled

// Bad
var foo = 1;
function bar() {}

// Good
window.foo = 1;
window.bar = function () {};

// Good
(function () {
	var foo = 1;
	function bar() {}
})();

disallow use of eval()-like methods

✅ Enabled (error)

// Bad
/*
setTimeout('doSomething();', 100);
*/

// Good
setTimeout(doSomething, 100);

disallow this keywords outside of classes or class-like objects

❌ Disabled

// Bad
foo(function () {
	this.a = 0;
});

disallow usage of iterator property

✅ Enabled (error)

// Bad
/*
Foo.prototype.__iterator__ = function () {
	return new FooIterator(this);
};
*/

disallow use of labels for anything other then loops and switches

✅ Enabled (error)

// Bad
/*
label:
	switch (a) {
		case 0:
			break label;
	}
*/

disallow unnecessary nested blocks

✅ Enabled (error)

// Bad
/*
{
	foo = bar();
}
*/

disallow creation of functions within loops

✅ Enabled (error)

// Bad
/*
for (var i = 0; i < 10; i++) {
	funcs[i] = function () {
		return i;
	};
}
*/

disallow magic numbers

❌ Disabled

// Bad
var now = Date.now(),
	inOneHour = now + (60 * 60 * 1000);

disallow use of multiple spaces

✅ Enabled (error)

// Bad
/*
if (foo  === 'bar') {}
*/

disallow use of multiline strings

✅ Enabled (error)

// Bad
/*
var x = 'Line 1 \
         Line 2';
*/

disallow reassignments of native objects

✅ Enabled (error)

// Bad
/*
String = new Object();
*/

disallow use of new operator for Function object

✅ Enabled (error)

// Bad
/*
var x = new Function('a', 'b', 'return a + b');
*/

disallows creating new instances of String, Number, and Boolean

✅ Enabled (error)

// Bad
/*
var stringObject = new String('Hello world');
var numberObject = new Number(33);
var booleanObject = new Boolean(false);
*/

// Good
var stringObject = String('Hello world');
var numberObject = Number(33);
var booleanObject = Boolean(false);

disallow use of new operator when not part of the assignment or comparison

✅ Enabled (error)

// Bad
/*
new Person();
*/

// Good
var person = new Person();

disallow use of octal escape sequences in string literals, such as var foo = 'Copyright \251';

✅ Enabled (error)

// Bad
/*
var foo = 'Copyright \251';
*/

disallow use of (old style) octal literals

✅ Enabled (error)

// Bad
/*
var num = 07;
*/

disallow reassignment of function parameters + disallow parameter object manipulation

❌ Disabled

// Bad
function foo(bar) {
	bar = 13;
}

disallow usage of proto property

✅ Enabled (error)

// Bad
/*
var a = obj.__proto__;
*/

disallow declaring the same variable more then once

✅ Enabled (error)

// Bad
/*
var a = 3;
var a = 10;
*/

disallow use of assignment in return statement

✅ Enabled (error)

// Bad
/*
function doSomething() {
	return foo = bar + 2;
}
*/

disallow use of javascript: urls.

✅ Enabled (error)

// Bad
/*
location.href = 'javascript:void(0)';
*/

disallow self assignment

✅ Enabled (error)

// Bad
/*
foo = foo;
*/

disallow comparisons where both sides are exactly the same

✅ Enabled (error)

// Bad
/*
var x = 10;
if (x === x) {
	x = 20;
}
*/

disallow use of comma operator

✅ Enabled (error)

// Bad
/*
var a = (3, 5); // a = 5
a = b += 5, a + b;
*/

// Good
var a = (3, 5);
// a = 5
a = (b += 5, a + b);

restrict what can be thrown as an exception

✅ Enabled (error)

// Bad
/*
throw 'error';
*/

// Good
throw new Error('error');

disallow unmodified conditions of loops

❌ Disabled

// Bad
var node;
while (node) {
	doSomething(node);
}
node = other;

// Good
var node = 1;
while (node) {
	doSomething(node);
	node = 2;
}

disallow usage of expressions in statement position

✅ Enabled (error)

// Bad
/*
a && b();
*/

disallow unused labels

✅ Enabled (error)

// Bad
/*
OUTER_LOOP:
	for (const student of students) {
		if (checkScores(student.scores)) {
			continue;
		}
		doSomething(student);
	}
*/

// Good
OUTER_LOOP:
	for (const student of students) {
		if (!checkScores(student.scores)) {
			break OUTER_LOOP;
		}
		doSomething(student);
	}

disallow unnecessary .call() and .apply()

❌ Disabled

// Bad
foo.call(undefined, 1, 2, 3);

// Good
foo(1, 2, 3);

disallow useless string concatenation

✅ Enabled (error)

// Bad
/*
var foo = 'a' + 'b';
*/

// Good
var foo = 'ab';

disallow unnecessary string escaping

✅ Enabled (error)

// Bad
/*
let foo = 'hol\a';
let bar = /\:/;
*/

// Good
let foo = 'hola';
let bar = /:/;

disallow use of void operator

✅ Enabled (error)

// Bad
/*
function test() {
	return void 0;
}
*/
// Good
function test() {
	return;
}

disallow usage of configurable warning terms in comments: e.g.

❌ Disabled

// TODO: do something
// FIXME: this is not a good idea

disallow use of the with statement

✅ Enabled (error)

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

require use of the second argument for parseInt()

✅ Enabled (error)

// Bad
/*
var num = parseInt('71');
*/

// Good
var num = parseInt('71', 10);

requires to declare all vars on top of their containing scope

❌ Disabled

// Bad
/*
function test() {
	var a = 1;
	var b = 2;

	if (a === 0) {
		// do something
	}

	var c = 3;
}
*/

// Good
function test() {
	var a = 1;
	var b = 2;
	var c;

	if (a === 0) {
		// do something
	}

	c = 3;
}


require immediate function invocation to be wrapped in parentheses

✅ Enabled (error)

// Bad
/*
var x = function () { return { y: 1 }; }();
*/

// Good
var x = function () { return { y: 1 }; };

require or disallow Yoda conditions

✅ Enabled (error)

// Bad
/*
if ('red' === color) {
	// ...
}
*/

// Good
if (color === 'red') {
	// ...
}