JavaScript Best Practices — Classes and Functions

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/

Cleaning up our JavaScript code is easy with default parameters and property shorthands.

In this article, we’ll look at the best practices when we create classes and functions.

Avoid Creating God Classes

God classes are classes that are all-knowing. If a class is mostly used for retrieving data from other classes using get and set methods, then we don’t need the class.

So if we have something like this:

class Foo {
  getBar() {}
  setBar() {}
  getBaz() {}
  setBaz() {}
  getQux() {}
  setQux() {}
}
Enter fullscreen mode Exit fullscreen mode

We can remove the class, and access the things we need directly.

Eliminate Irrelevant Classes

If we need a class, then we should remove it.

This applies to classes that only have data. If we have members that are in the class, then we should consider if they should be members of another class instead.

Avoid Classes Named After Verbs

We shouldn’t name classes with verbs since a class that has only behavior but not data shouldn’t be a class.

For instance, if we have:

class GetFoo {
  //...
}
Enter fullscreen mode Exit fullscreen mode

Then it should be a function instead of a class.

When Should We Create Functions?

We should create functions to make our code better. The following are the reasons for creating functions.

Reduce Complexity

Reducing complexity is one of the most important reasons for creating functions.

We got to create them so that we don’t repeat code and minimizing code size.

If we write all procedures without functions, then we would have lots of similar code.

For instance, if we have:

const greet1 = `hi joe`;
const greet2 = `hi jane`;
Enter fullscreen mode Exit fullscreen mode

Then we can make a function to generalize that:

const greet = (name) => `hi ${name}`;
const greet1 = greet('joe');
const greet2 = greet('jane');
Enter fullscreen mode Exit fullscreen mode

Now we can call greet anywhere to create similar strings.

Introduce an Intermediate, Understandable Abstraction

The code above is also an abstraction. We generalized the code for returning greeting strings.

We can pass in different values of name and return a new string.

Avoid Duplicate Code

Avoiding duplicate code is also a good reason for creating functions.

Again, as we can see from the example above, we can call greet to create many more of the same strings.

Then we don’t have to repeat the hi part everywhere.

Support Subclassing

We can create a method in a subclass to override a method in the superclass.

For instance, we can write the following code to do that in JavaScript:

class Animal {
  constructor(name) {
    this.name = name;
  }
  speak() {
    return `${this.name} speaks`;
  }
}

class Dog extends Animal {
  constructor(name) {
    super(name);
  }
  speak() {
    return `${super.speak(this.name)} in dog language`;
  }
}
Enter fullscreen mode Exit fullscreen mode

We have overridden the speak method in Dog by calling super.speak .

Therefore, we can keep the speak method in Dog simpler.

Photo by Danielle Cerullo on Unsplash

Hide Sequences

Functions are good for hiding implementations of procedures.

For instance, we can have a function that calls other functions and do something with them.

We can write:

const calcWeight = () => {
  //...
}

const calcHeight = () => {
  //...
}

const calcWidth = () => {
  //...
}

const getAllDimensions = () => {
  const weight = calcWeight();
  //...
  const height = calcHeight();
  //...
  const width = calcWidth();
  //...
}
Enter fullscreen mode Exit fullscreen mode

We called multiple functions in the code above. But other parts of our program won’t know the order that they’re called.

This reduces the implementation that is exposed and reduces coupling.

Improve Portability

Functions can be moved anywhere easily. We can move it and anything else that depends on it easily.

Simplify Complicated Boolean Tests

If we have long boolean expressions, then we should put them into their own function.

For instance, if we have:

const isWindowsIE = navigator.userAgent.toLowerCase().includes('windows') &&
  navigator.userAgent.toLowerCase().includes('ie');
Enter fullscreen mode Exit fullscreen mode

Then we can put the whole thing into a function by writing:

const isWindowsIE = () => {
  const userAgent = navigator.userAgent.toLowerCase()
  return userAgent.includes('windows') &&
    userAgent.includes('ie');
}
Enter fullscreen mode Exit fullscreen mode

It’s just much cleaner than having long boolean expressions.

Conclusion

God classes, classes that only data or behavior are all bad. We should make sure that we have a mix before creating both.

We create functions to reduce complexity, remove duplicate code, and make abstractions.

They’re good for creating anything.

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