To make code easy to read and maintain, we should follow some best practices.
In this article, we’ll look at some best practices we should follow to make everyone’s lives easier.
No Duplicate Conditions in if-else-if
Chains
We shouldn’t have duplicate conditions in if-else-if chains.
Only the first one will run.
So instead of writing:
if (isSomething(x)) {
foo();
} else if (isSomething(x)) {
bar();
}
We write:
if (isSomething(x)) {
foo();
} else if (isSomethingElse(x)) {
bar();
}
No Duplicate Keys in Object Literals
We shouldn’t have duplicate keys in object literals.
For instance, we shouldn’t have objects like:
const foo = {
bar: "baz",
bar: "bar"
};
Instead, we write:
const foo = {
bar: "baz"
};
No Duplicate Case Label
We shouldn’t have duplicate case
labels in our code.
For instance, instead of writing:
switch (a) {
case 1:
break;
case 2:
break;
case 1:
break;
default:
break;
}
We write:
switch (a) {
case 1:
break;
case 2:
break;
default:
break;
}
No Duplicate Imports
We shouldn’t have multiple, import
statements for one module.
For instance, instead of writing:
import { merge } from 'module';
import something from 'foo';
import { find } from 'module';
We write:
import { merge, find } from 'module';
import something from 'foo';
No return Before else
If we’re writing a return
statement, then we can remove the else
For instance, we can write:
function foo() {
if (x) {
return y;
}
return z;
}
instead of writing:
function foo() {
if (x) {
return y;
} else {
return z;
}
}
No Empty Block Statements
Empty blocks aren’t very useful, so we should fill them with something or remove them.
For instance, the following aren’t very useful:
if (bar) {}
while (bar) {}
switch (bar) {}
try {
doSomething();
} catch (ex) {
} finally {
}
for (;;){}
Instead, we fill them with something.
Empty Character Classes in Regex
We shouldn’t have empty character classes in regex since they don’t match anything.
For instance, we should have code like:
/^foo[]/.test("foobar");
"foobar".match(/^foo[]/);
Instead, we should fill the brackets with a pattern:
/^foo[a-z]/.test("foobar");
"foobar".match(/^foo[a-z]/);
No Empty Functions
We shouldn’t have empty functions in our code.
They don’t do anything.
For instance, instead of writing:
function foo() {
}
We write:
function foo() {
doSomething();
}
No Empty Destructuring Patterns
Empty destructuring patterns do nothing, and they’re easily mistaken for empty objects as the default value.
For instance:
const {a: {}} = foo;
is easily mistaken for:
const {a = {}} = foo;
The first is an empty destructuring pattern.
The 2nd is using the empty object as the default value.
No Null Comparisons
Comparing null
using ==
or !=
can have unintended consequences because of the data type coercion.
Therefore, we should use ===
or !==
to do the comparison.
Instead of writing:
if (foo == null) {
bar();
}
while (qux != null) {
bar();
}
We write:
if (foo === null) {
bar();
}
while (qux !== null) {
bar();
}
No Calls to eval()
eval
lets us run JavaScript code from a string.
But we shouldn’t use it since it’s insecure to run code from a string.
Performance optimizations also can’t be done on code that’s in a string.
Instead of writing:
eval("let a = 0");
We write:
let a = 0;
No Reassigning Exceptions in catch
Clauses
We shouldn’t reassign exceptions ib catch
clauses.
If we do, then we lose data from the exception.
So instead of writing;
try {
// code
} catch (e) {
e = 10;
}
We write:
try {
// code
} catch (e) {
const foo = 1;
}
Don’t Extend Native Objects
We shouldn’t extend built-in objects, even though we’re allowed to.
For instance, we shouldn’t write code like:
Object.prototype.foo = 55;
to add properties to a built-in constructor.
Using defineProperty
is also bad:
Object.defineProperty(Array.prototype, "bar", { value: 999 });
Conclusion
We shouldn’t have duplicate conditions, keys, or case
labels.
Also, we should never use eval
.
And we shouldn’t extend native objects.
Empty destructuring patterns are also useless and deceptive.
We should compare null
with ===
or !==
.