JavaScript Best Practices: More Things to Avoid

John Au-Yeung - Jan 27 '21 - - Dev Community

Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62

Subscribe to my email list now at http://jauyeung.net/subscribe/

Like any other programming language, JavaScript has its own list of best practices to make programs easier to read and maintain. There are lots of tricky parts to JavaScript, so there are many things to avoid.

We can follow some best practices to make our JavaScript code easy to read.

In this article, we look at more constructs that we should avoid, including the misuse of the for...in loop, the == operator, the arguments object, and this.


Misusing the For…in Loop

The for...in loop shouldn’t be used to iterate through arrays and array-like objects. For example, if we have:

const arr = ['a', 'b', 'c', 'd', 'e'];
for (let i in arr) {
  console.log(i)
}
Enter fullscreen mode Exit fullscreen mode

We get back:

0
1
2
3
4
Enter fullscreen mode Exit fullscreen mode

However, this is a misuse of the for...in loop since it’s supposed to iterate through the enumerable properties of an object and its prototype rather than looping through the indexes of an array.

The order of the enumeration isn’t guaranteed, so we might not loop through the array in order, which is bad.

The for...in loop also loops through inherited properties that are enumerable, which is another problem.

For example, if we have:

Then we create an object with a prototype object with the foo property. The for...in loop will loop through both the enumerable properties of obj’s prototype and obj.

To avoid looping through the properties of its prototype, we can use Object.keys instead:

for (let prop of Object.keys(obj)) {
  console.log(prop);
}
Enter fullscreen mode Exit fullscreen mode

We can loop through the key-value pair of obj without anything from its prototype, we can use Object.entries:

for (let entry of Object.entries(obj)) {
  console.log(entry);
}
Enter fullscreen mode Exit fullscreen mode

For looping through arrays and array-like objects, we should use the for...of loop instead:

const arr = ['a', 'b', 'c', 'd', 'e'];
for (let a of arr) {
  console.log(a)
}
Enter fullscreen mode Exit fullscreen mode

Then we get the entries of the array.


Messing With this

The this object is always a problem in JavaScript. This is because it changes depending on the scope.

Fortunately, in ES6, we have arrow functions that don’t change the value of this if we reference it inside. This also means that we can’t change the value of this with call, bind, or apply.

For example, the following code will log the window object:

The value of this doesn’t change even if we try to change it with bind.

Also, ES6 has the class syntax for creating constructor functions so it’s clear that this should be inside the class as long as we use class methods and arrow functions.

Class methods will have the class as the value of this and arrow functions inside the class will have the same value for this.

Photo by Casey Allen on Unsplash


The == Operator

The == operator does automatic type conversion before comparing the operands for equality. This creates issues with different types of data being considered the same.

For example, null == undefined returns true, which we probably don’t want.

null == undefined returns true because they’re both falsy.

To avoid these kinds of issues, we should use the === operator instead, which would avoid comparisons of these kinds of operands returning true. This is because === checks the type of each operand in addition to the operand’s contents.


The arguments Object

With the introduction of the rest operator, we can finally avoid the use of the arguments object for getting the arguments that were passed into a function.

The arguments object shouldn't be used for a few reasons. One is that it’s an array-like object, which means properties like length are in it and it can be looped through with a for loop, but array methods like map and forEach aren’t included in it.

Also, we can access its entries with its index, which is deceiving since it’s not actually an array.

Using arguments also prevents any code optimization by browser engines, which means performance is slower. Also, the arguments object isn’t available in arrow functions.

Therefore, to access extra arguments that are beyond the parameters listed, we should use the rest operator instead.

For example, instead of writing:

We can write:

const add = (...args) => args.reduce((a, b) => a + b, 0);
console.log(add(1, 2, 3, 4, 5));
Enter fullscreen mode Exit fullscreen mode

Notice that it’s much shorter to use the rest operator, which is the ...args part of the function signature. args is already an array so we have all the array methods available for us to use.


Conclusion

In modern JavaScript, we can abandon a lot of older constructs to make our code easier to read and maintain.

We can use the rest operator instead of the arguments object. This is because the rest operator gives us an array of arguments instead of the array-like arguments object.

Also, we should avoid the == operator for equality comparison since it does automatic type conversion before comparing which we might not want.

We should also avoid messing with this by using arrow functions and class syntax for constructor functions. These two constructs make the value of this a lot clearer. We only use class methods for classes and arrow functions for functions that aren’t a method of a class.

Finally, the for...in loop shouldn’t be used for looping through arrays and array-like objects since the order of enumeration isn’t guaranteed to be in order, leading to unexpected results.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .