Staunch functional proponents will fire up at the mere mention of classes or any form of object-oriented programming. These arguments go way back to before Javascript was even a thing or as popular as it is now.
Let’s clear the air and point out that classes in Javascript are not real classes. They’re often compared to the likes of Java and other languages that promote OOP-style programming, but classes in JS are unlike those implementations. Javascript has prototypes and prototypes are not classes.
When the ES2015 Javascript standard was released (its biggest update ever), a plethora of new and exciting features came with it. New syntax and API’s, in the mix, was classes (sugar over conventional prototypal inheritance). Perhaps the most controversial addition of them all.
Here is the one thing that class opponents forget: classes in Javascript are optional. They’re not being forced on developers, you either use them or you don’t use them. It is really that simple. And yet, the arguments and noise around their inclusion (especially 2015/2016) you would be forgiven for thinking they’re a requirement to program in Javascript.
Inheritance
One of the biggest downsides to object-oriented programming and classes is inheritance. I am a fan of OOP style programming and even I agree that inheritance can be a nightmare and paint you into a corner.
But here is a secret that functional programming proponents don’t want you to know: inheritance is optional.
I use classes in my Aurelia applications and I avoid inheritance whenever possible. If I do use inheritance (which sometimes I do) I will be strict about it and only have one level of inheritance (parent-child relationship). More than one level of inheritance is a recipe for a bad time. I also try and avoid super
calls as well.
Not all uses of inheritance are bad, it can be useful when you want to avoid duplicating code between multiple classes. If you’re building a widget-based component UI and your components all share similar implementation details except for a few configuration-specific pieces of data, inheritance works well here.
In many cases, I use classes as structs for modelling specific pieces of data in my applications, for example:
export class UserModel { constructor(name, email) { this.name = name; this.email = email; } }
I actually prefer the aesthetics of a class over a function. I also love how I have to use the new
keyword to explicitly create a new instance of my UserModel
.
But the argument that you shouldn’t use classes because it is easier to fall into certain traps is nonsense. Javascript is a language full of traps that extend beyond the likes of classes which are quite low on the scale of JS gotchas.
If you are also working with TypeScript, the benefits of classes are even better when you throw collections and generics into the mix. The development experience just makes sense. I let the TypeScript compiler decide if my classes should be transpiled to functions, prototypes or classes.
I’ve read quite a lot on the subject of OOP and the main argument always seems to boil down to inheritance, followed by personal preference.
Composition <> Inheritance
Whenever the classes vs functions debate arise, people take sides and stances on one side or the other. The truth is you should not and do not have to choose a side, you can use both.
You can still use classes where they make sense and in other parts, use functions where they make sense. Sometimes you just need simple functions and other times, you might like the semantics of a class for organising your code.
If you are implementing a feature/writing code and a function feels appropriate, write a function. If a class feels more appropriate, use a class instead.
Web Components
If you head over to the Google fundamentals for creating custom elements or Mozilla MDN in Web Components, surprise surprise you will find classes are what you use to author custom elements.
Sure, you could just directly write the prototype chain yourself, but it’s going to result in ugly code that is just painful to maintain. The sweet syrupy abstraction that classes provide here is immediately obvious from an aesthetics perspective.
I think classes make a lot of sense when creating custom elements. You’re extending the inbuilt element type and creating your own variant of it. One of the things that classes do well.
Frameworks + First-Class Citizens
Angular and Aurelia are two fully-featured front-end frameworks that have leveraged Javascript classes since the beginning in 2015. I have quite a few Aurelia applications in production, all leveraging classes, sprinkled with a function or two.
The rewrite of Angular (Angular 2+) also treats classes as a first-class citizen. While React might be the most popular option out there, in the enterprise and government sectors, Angular is the king. A lot of Australian government agency applications are built using Angular.
I have not seen or heard of any developer, agency or company running into any kind of problem as a result of classes being a requirement to build Aurelia or Angular applications. If you have, I would love to know.
In instances where classes cause problems, it is because the developer using them is to blame. A bad mechanic blames their tools.
Ignore The Noise, Form Your Own Opinions
I don’t pretend to have all of the answers or be the worlds greatest coder, but I know what works for me based on my years of experience. Be wary of anyone who argues there is only one right way to develop in Javascript because there isn’t.
There are quite a few prominent figures in the JS community who will vehemently argue against classes. They will tell you they have seen companies lose millions, go bankrupt and projects completely scrapped because of classes.
Most of the anti-class crowd have an agenda. You will discover the common thread amongst most anti-class dev-influencers is they’re selling training courses and other material. They will tell you there is only one way to do something and to signup for their “Right Way of Doing Things” course for developers.
One person’s right is another person’s wrong.