JavaScript Best Practices: Useless Code, Comparisons, and Eval

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/

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 JavaScript best practices to follow, including avoiding empty function and destructuring, null comparison, avoiding useless bind and avoid eval.


Don’t Write Empty Functions

Empty functions aren’t useful and we don’t know if they’re intentional or not. This means that we should at least write a comment to let people know whether it’s intentional.

This also goes for arrow function callbacks that return nothing, since they look similar to an empty object.

For instance, we should avoid:

function foo() {}
arr.map(() => {});
arr.map(() => ({}));
Enter fullscreen mode Exit fullscreen mode

Instead, we should write:

function foo() {
  // do nothing
}
Enter fullscreen mode Exit fullscreen mode

or:

arr.map(() => {}); // returns nothing
Enter fullscreen mode Exit fullscreen mode

or:

arr.map(() => ({})); // returns empty object
Enter fullscreen mode Exit fullscreen mode

Empty Destructuring Patterns

Empty destructuring patterns are also useless, so there’s no point in creating them. For instance, the following isn’t useful:

const {a: {}} = foo;
Enter fullscreen mode Exit fullscreen mode

It might also be mistaken for setting a to an empty object as the default value as follows:

const {a = {}} = foo;
Enter fullscreen mode Exit fullscreen mode

We should avoid having empty destructuring patterns in our code. If we have any, we can and should remove them.


Null Comparisons with ==

null comparisons with == or != also compares the operand we’re comparing with other values with undefined . Therefore, the following are also true if we compare foo with null in the following code:

let foo = undefined;
foo == null;
Enter fullscreen mode Exit fullscreen mode

We get that foo == null returns true, which is probably not what we want. Likewise, if we have the following comparison with !=:

let foo = undefined;
foo != null;
Enter fullscreen mode Exit fullscreen mode

We get that foo != null is false even though foo is undefined . Therefore, we should instead use === and !== to check for null as follows:

let foo = undefined;
foo === null;
Enter fullscreen mode Exit fullscreen mode

and:

let foo = undefined;
foo !== null;
Enter fullscreen mode Exit fullscreen mode

Never Use eval()

eval lets us pass in a string with JavaScript code and run it. This is dangerous because it can potentially let anyone run JavaScript code that we didn’t write. It can open up our program to several kinds of injection attacks.


No Extension of Native Objects

In JavaScript, we can extend any native objects with their own methods. However, that’s not a good idea because it may break other pieces of code that use native objects in ways that we don’t expect.

For instance, if we have the following:

Object.prototype.foo = 55;

const obj = {
  a: 1,
  b: 2
};

for (const id in obj) {
  console.log(id);
}
Enter fullscreen mode Exit fullscreen mode

We see that foo is logged in addition to a and b because the for...in loop iterates through all enumerable properties in the current object and the object’s prototype chain.

Since JavaScript extends the JavaScriptObject object by default, the for...in loop will also loop through enumerable properties in the Object’s prototype.

Therefore, we shouldn’t extend native objects as it may do things that we don’t expect to other code.


No Unnecessary Function Binding

The bind method is a method of a function that changes the value of this inside a traditional function. Therefore, if our function doesn’t reference this, then we don’t need to call bind on it to change the value of this.

For example, the following function uses bind with a purpose:

function getName() {
  return this.name;
}
const name = getName.bind({
  name: "foo"
});
console.log(name());
Enter fullscreen mode Exit fullscreen mode

In the code above, we have the getName function, then we called bind on it to change the value of this to { name: “foo” }. Then we when we call name in the last line, we see return this.name , which should be 'foo' since we changed the value of this to the object.

On the other hand, if we have:

function getName() {
  return 'foo';
}
const name = getName.bind({
  name: "foo"
});
console.log(name());
Enter fullscreen mode Exit fullscreen mode

Then the call to bind is useless since getName didn’t reference this. Therefore, if our function doesn’t reference this, then we don’t need to call bind on it.


Conclusion

Comparing null with == isn’t very useful since expressions like undefined == null also return true because of type coercion. To ensure attackers can’t run malicious code, eval shouldn’t be called.

bind is useless if we don’t reference this in our function, so if we do call it, we should make sure that we have this in our function. Other things like empty functions and destructuring patterns are useless, so they should be avoided.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Terabox Video Player