JavaScript is a very forgiving language. It’s easy to write code that runs but has mistakes in it.
In this article, we’ll look at some best practices when writing JavaScript code, including comparisons, accessors, objects, and loops.
=== and !== are Better Than == and !=
===
and !==
saves us a lot of trouble from JavaScript type coercion. The algorithm for comparison using ==
and !=
because of it.
With ==
we get results like:
[] == false
[] == ![]
2 == "02"
all of which return true
.
There’s a lot list of rules that we have to aware of listed at https://www.ecma-international.org/ecma-262/5.1/#sec-11.9.3 for ==
and !=
.
Therefore to avoid remembering all that and avoid weird results like the ones that are listed above, we should use ===
and !==
for comparison.
So, we should avoid writing the following code:
if (x == 1) {
}
and instead, write:
if (x === 1) {
}
Other examples of good code include:
a === b
foo === true
apple !== 1
value === undefined
typeof foo === 'undefined'
'foo' !== 'bar'
Grouping Accessor Pairs in Object Literals and Classes
Grouping getters and setters for the same field together makes sense. It’s easier to read and we won’t have to search for them all over the code.
For instance, instead of writing:
const obj = {
get a() {
return this.val;
},
b: 1,
set a(val) {
this.val = val;
}
}
and:
class Foo {
get a() {
return this.val;
}
b() {
return 1;
}
set a(val) {
this.val = val;
}
}
We should instead write:
const obj = {
get a() {
return this.val;
},
set a(val) {
this.val = val;
},
b: 1,
}
and:
class Foo {
get a() {
return this.val;
}
set a(val) {
this.val = val;
}
b() {
return 1;
}
}
Checking for Own Properties in for…in Loops
for...in
loop loops through an object’s own properties and also the properties up the prototype chain.
This will lead to unexpected items being looped through within the loop.
To avoid this, we should add a check to see if we’re looping through an object’s own properties so that we don’t accidentally loop through an object’s prototype’s properties.
Therefore, instead of writing:
for (const key in foo) {
console.log(foo[key]);
}
We should write the following code instead:
for (const key in foo) {
if (Object.prototype.hasOwnProperty.call(foo, key)) {
console.log(foo[key]);
}
}
The following code is also good:
for (const key in foo) {
if ({}.hasOwnProperty.call(foo, key)) {
console.log(foo[key]);
}
}
In both examples, we called hasOwnPropterty
with the call
method to change the this
value in hasOwnProperty
to foo
and pass in the key
as the first argument to hasOwnProperty
so that we can check if the key
is in foo
itself.
Don’t Have Too Many Classes Per File
Having too many classes per file makes it harder and read and navigate. The structure is also worse.
It’s best to limit each code file to a single responsibility. For instance, instead of writing in one file:
class Foo {}
class Bar {}
We should split them into 2 files:
foo.js
:
class Foo {}
bar.js
:
class Bar {}
Photo by Syed Ahmad on Unsplash
Disallow Use of Alert
JavaScript’s alert
, confirm
, and prompt
functions are obtrusive as UI elements and should be replaced with modals, dialogs, or something else that’s less obtrusive.
It’s also often used for debugging code. Therefore, we should avoid using them unless we’re actually using them for alerting users and asking questions.
Even then, they should be used sparingly.
Stop Using arguments.caller
and arguments.callee
arguments.caller
and arguments.callee
makes some code optimizations impossible. They’re also forbidden in strict mode.
They also don’t work in arrow functions since they don’t bind to arguments
.
Therefore, we should either use arrow functions if we don’t need to bind to this
. If we need to use traditional functions, then we shouldn’t reference those 2 properties in our function.
So:
function foo() {
var callee = arguments.callee;
}
or:
function foo() {
var caller = arguments.caller;
}
would be bad code that we want to avoid.
The alternative would be to reference the caller and callee functions directly. So arguments.callee
would be foo
.
Conclusion
We should use ===
and !==
for comparison to avoid the confusing outcomes of the ==
and !=
comparison operators.
If we use accessors, then we should group the same value accessors together.
Also, maximum classes per file should be limited. The fewer the better. This limits any code file to a single responsibility.
Alerts, confirmation, and prompt pop-ups should be used as sparingly as possible.
Finally, we shouldn’t use arguments.caller
and arguments.callee
in traditional functions.