JavaScript Refactoring — Class Refactoring

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.

Pull Up Constructor Body

If we have multiple constructor bodies in our subclasses with overlapping code, we can move them to the superclass.

For instance, if we have the following code:

class Employee {

}

class Cook extends Employee {
  constructor(name, level) {
    this.name = name;
    this.level = level;
  }
}

class Manager extends Employee {
  constructor(name) {
    this.name = name;
  }
}
Enter fullscreen mode Exit fullscreen mode

We can move the common code in both constructors to the superclass as follows:

class Employee {
  constructor(name) {
    this.name = name;
  }
}

class Cook extends Employee {
  constructor(name, level) {
    super(name)
    this.level = level;
  }
}

class Manager extends Employee {

}
Enter fullscreen mode Exit fullscreen mode

In the code above, we move the code for setting the name field to the Employee class to avoiding duplicating that in the Cook and Manager classes.

Push Down Method

If we have superclass methods that are only used by an instance of one subclass, then we should move it to the subclass.

For instance, if we have the following code:

class Employee {
  speak() {
    //...
  }
}

class Cook extends Employee {

}

class Manager extends Employee {

}

const cook = new Cook();
cook.speak();
Enter fullscreen mode Exit fullscreen mode

Since speak is only called by a Cook instance, we can move it to the Cook class:

class Employee {

}

class Cook extends Employee {
  speak() {
    //...
  }
}

class Manager extends Employee {

}

const cook = new Cook();
cook.speak();
Enter fullscreen mode Exit fullscreen mode

This way, we can reduce the clutter of our superclass.

Push Down Field

We push down a field that’s only used in one or a few subclasses to the subclass itself.

For instance, instead of writing the following code:

class Employee {
  constructor(subordinates) {
    this.subordinates = subordinates;
  }
}

class Cook extends Employee {

}

class Manager extends Employee {

}
Enter fullscreen mode Exit fullscreen mode

We can put the subordinates field to the Manager class as follows:

class Employee {
  //...
}

class Cook extends Employee {
  //...
}

class Manager extends Employee {
  constructor(subordinates) {
    this.subordinates = subordinates;
  }
}
Enter fullscreen mode Exit fullscreen mode

The subordinates field only applies to Manager so it should be there.

Extract Subclass

If we have a class that has features that are only used by some instances, then it should be extracted to its own subclass.

For instance, if we have the following code:

class Employee {
  //...
  getSubordinates() {
    //...
  }
}
Enter fullscreen mode Exit fullscreen mode

Then since getSubordinates isn’t used by all Employee instances, we can extract it as follows:

class Employee {
  //...
}

class Manager extends Employee {
  //...
  getSubordinates() {
    //...
  }
}
Enter fullscreen mode Exit fullscreen mode

This way, we don’t have to clutter up the Employee class with methods that not all instances need.

Extract Superclass

If we have 2 or more classes with similar features, then we should move the shared members to a superclass.

Then the existing classes can be subclasses of the superclass.

For instance, if we have the following code:

class Cat {
  //...
  speak() {
    //...
  }
}

class Dog {
  //...
  speak() {
    //...
  }
}
Enter fullscreen mode Exit fullscreen mode

Then we can create a new class with the speak method and make Cat and Dog subclasses of that class as follows:

class Animal {
  //...
  speak() {
    //...
  }
}

class Cat extends Animal {

}

class Dog extends Animal {

}
Enter fullscreen mode Exit fullscreen mode

Now we don’t have any more duplication.

Photo by NeONBRAND on Unsplash

Collapse Hierarchy

If the subclass and superclass aren’t too different, then we can combine them into one.

For instance, if we have the following:

class Animal {
  //...
  speak() {
    //...
  }
}

class Cat extends Animal {
  //...
}
Enter fullscreen mode Exit fullscreen mode

We can combine them as follows:

class Animal {
  //...
  speak() {
    //...
  }
}
Enter fullscreen mode Exit fullscreen mode

Since the Cat class didn’t have many extra things we need, we can just remove it.

Any overly complex class hierarchy isn’t good.

Conclusion

We can remove duplicate from multiple classes by moving common code to a superclass.

If we don’t need much in a subclass, then we can remove it and combine all the members into one class.

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