JavaScript Refactoring — More Conditionals

John Au-Yeung - Jan 25 '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/

We can clean up our JavaScript code so that we can work with them more easily.

In this article, we’ll look at some refactoring ideas that are relevant for cleaning up JavaScript conditionals.

Introduce Assertion

We can add assertions to check for the parameters passed in by adding assertions.

This way, assumptions are made explicit.

For instance, we can write the following to add an assertion:

const assert = require('assert');
const foo = (val) => {
  assert.equal(val, 50);
  //...
}
Enter fullscreen mode Exit fullscreen mode

The code above works for Node.js since it uses the Node.js’s assert module.

We check if val is 50 before proceeding. If the assertion is false, the function will end.

Rename Method

If our method name isn’t clear enough, then we should rename it so that it’s clearer.

For instance, instead of writing:

class Person {
  ga() {
    //...
  }
}
Enter fullscreen mode Exit fullscreen mode

We write:

class Person {
  getAge() {
    //...
  }
}
Enter fullscreen mode Exit fullscreen mode

getAge is much clearer than ga , so we should rename it.

Add Parameter

We can also add parameters to methods. For instance, instead of writing:

class Person {
  getContact() {
    //...
  }
}
Enter fullscreen mode Exit fullscreen mode

We write:

class Person {
  getContact(date) {
    //...
  }
}
Enter fullscreen mode Exit fullscreen mode

We added the date parameter to make getting what we want easier.

Separate Query From Modifier

If we have a method that returns and value and changes the state of the object, then we should break them up into separate methods.

This way, they only do one thing each.

For example, instead of writing:

class Purchase {
  setPurchaseDateAndGetTotalPrice() {
    //...
  }
}
Enter fullscreen mode Exit fullscreen mode

We write:

class Purchase {
  setPurchaseDate() {
    //...
  }

  getTotalPrice() {
    //...
  }
}
Enter fullscreen mode Exit fullscreen mode

Not only the names of the methods are shorter, but their bodies also do less and only one thing so it’s better.

Parameterize Method

Instead of having multiple methods doing similar things, we can have one method that takes a parameter that does something that all the methods do.

For instance, instead of writing:

class Purchase {
  fivePercentDiscount() {
    //...
  }

  tenPercentDiscount() {
    //...
  }
}
Enter fullscreen mode Exit fullscreen mode

We write:

class Purchase {
  discount(percent) {
    //...
  }
}
Enter fullscreen mode Exit fullscreen mode

Replace Parameter with Explicit Methods

If we have a method with parameters and different things are done according to those parameters, we can separate them out into their own methods.

For instance, instead of writing:

class Person {
  getDimension(type) {
    if (type === 'height') {
      return this.getHeight();
    } else if (type === 'weight') {
      return this.getWeight();
    }
  }

  getHeight() {
    ///...
  }

  getWeight() {
    ///...
  }
}
Enter fullscreen mode Exit fullscreen mode

We write:

class Person {
  getHeight() {
    ///...
  }

  getWeight() {
    ///...
  }
}
Enter fullscreen mode Exit fullscreen mode

As we can see, the getDimension isn’t all that useful to begin with, so we can remove it and call those getHeight and getWeight directly.

Preserve Whole Object

If we have to get multiple values from an object and pass them all into a function, then we should just pass in the whole object instead.

For instance, instead of writing:

const calculate = (height, weight) => {
  //...
}

const height = getDimensions().height;
const weight = getDimensions().weight;
calculate(height, weight);
Enter fullscreen mode Exit fullscreen mode

We write:

const calculate = ({
  height,
  weight
}) => {
  //...
}

const dimensions = getDimensions();
calculate(dimensions);
Enter fullscreen mode Exit fullscreen mode

We just pass in the whole object instead of passing in individual properties.

To make the calculate function more readable, we used destructuring to get the properties that we want to get from the object.

Replace Parameter with Method

We can replace a parameter with its own method. For instance, if we have:

const getDiscountLevel = () => {
  //...
  return 0.5;
};

const discountedPrice = (subtotal, discountLevel) => {
  return subtotal * discountLevel
}
const subtotal = 100
const discountLevel = getDiscountLevel();
const total = discountedPrice(subtotal, discountLevel);
Enter fullscreen mode Exit fullscreen mode

We can just replace discountLevel with the getDiscountLevel function call itself as follows:

const getDiscountLevel = () => {
  //...
  return 0.5;
};

const discountedPrice = (subtotal) => {
  return subtotal * getDiscountLevel()
}
const subtotal = 100
const total = discountedPrice(subtotal);
Enter fullscreen mode Exit fullscreen mode

Now we eliminated the parameter from discountedPrice and the discountLevel variable.

Conclusion

To add checks to a function before it’s run, we add some assertions with the Node assert module.

We can also rename methods to make them clearer. Also, methods that do multiple things should be broken down.

If we’re passing in multiple properties from the same object into a function, we should just make the function take the whole object.

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