What’s Wrong with Classes in JavaScript?

I’m all for syntactic sugar, but we’re still missing a few things.

Fernando Doglio
Bits and Pieces
Published in
6 min readDec 31, 2020

--

Image by baerbelborn from Pixabay

It’s not that there is something wrong with JavaScript’s classes, but if you’ve been working with the language for a while, especially if you’ve worked with ES5 before, you’ve probably seen the evolution from Prototypal inheritance into the current class model.

Why though? What was wrong with the prototype chain?

The answer to that question, in my humble opinion, is: nothing. But the community spent years forcing the concept of classes into different constructs and libraries, so the ECMA Technical Committee decided to add it anyway.

The problem with that, you ask? Is that all they really did, was to add some makeup on top of the prototypal inheritance we already had and decided to call it “classes”, which in turn, gives developers the idea that they’re dealing with an Object-Oriented language when they’re really not.

Classes are nothing more than syntactic sugar

JavaScript does not have full OOP support, it never did, and that is because it’s never needed it.

At a surface level, the current version of classes shows an OOP paradigm, because:

  • We can create our basic class definition, grouping state and behavior together with a very classic syntax.
  • We can inherit from one class to the other.
  • We can define the visibility of our properties and methods, between public and private (although private fields are still an experimental feature).
  • We can define getters and setters for our properties.
  • We can override methods during class inheritance.
  • We can, of course, instantiate our classes.

So why am I saying classes are syntactic sugar? Because although at surface level, they might seem very “object-oriented”, if we try to do something outside of their realm of possibility, such as defining one class that extends two others (something that’s not currently possible), we need to use the following code:

We need to do this, because in JS we can’t write:

And because there are cases where such behavior might come in handy, the folks from TypeScript created the above snippet, I just removed the extra code to make it work for vanilla JS.

But the key takeaway from the sample code should be the applyMixins function. Even if you don’t fully understand what it is trying to do, you can clearly see that it’s accessing the prototype properties of all classes to copy and re-assign the methods and properties. That’s all the proof you need to see the truth: classes are nothing more than syntactic sugar on top of the tried and true prototypal inheritance model.

Does that mean we should stop using classes? Not at all, but it’s important to understand it, and the fact that if you ever need to push the boundaries of that classes can and can’t do, you’ll have to deal with prototypes to do so.

What’s missing from JavaScript’s OOP model then?

If our current OOP model is so thin and barely anything more than a layer of abstraction over prototypal inheritance, what exactly are we missing? What could make JS truly OOP?

A good way of looking at this question is to just look at what TypeScript is doing. The team behind that language is definitely pushing JavaScript to the limits by creating something that can be translated into JS. This in turn, is also limiting their capabilities, but a good way to start our OOP wishlist would be to look at their OOP-related features:

There is one caveat that you’ll notice in a second: some of the missing OOP constructs in JavaScript right now, have an intrinsic type-checking functionality that has no real meaning inside a dynamically typed language, which is probably why they haven’t been added yet.

Interfaces

These are great constructs to help define the API a class should comply with. One of the main benefits of interfaces, that would be lost inside typeless JS, is the fact that you could define a variable of any class implementing the same interface and safely call any of its methods.

This can’t be done in plain JS

You can definitely achieve the same thing with a class defining the speak method, and then overwriting it. But then again, you can also do that in any other strongly OOP language. Interfaces are cleaner and more elegant.

Abstract classes

I definitely do miss abstract classes from JS whenever I try to go full OOP with my code. An abstract class is one that defines and implements methods, but that will never be instantiated. It is a way of grouping common behavior that can be extended but never directly used. It’s a great resource and it’s definitely something that could be implemented within the current realm of JS without breaking too much.

Static polymorphism

I personally liked this one from my OOP days, and sometimes feel like it would come in handy if we had it supported in JS as well. Static polymorphism allows us to have the same method defined several times within the same class, but with different signatures. In other words, have the name repeated but make sure it receives different parameters. We have rest parameters now with JS, and this allows us to have an arbitrary number, however, it also means we have to add extra code to our method to handle this level of dynamism. If instead, we could differentiate method signatures more clearly, we would be able to directly encapsulate different flavors of the same behavior into different methods.

The left version is not valid JS, but it provides a cleaner code and thus, it requires less cognitive load to mentally parse. The version on the right, however, is completely valid. It requires a bit of mental parsing and it has more code around it because it’s not only logging (which should be its only purpose) but it’s also trying to decide HOW to log, based on the parameters you provided.

Static polymorphism is usually implemented by looking at the types of parameters received in the methods. However, because of how JS works, we know that wouldn’t be possible.

Protected properties and methods

We already have public visibility, and we’re soon getting private visibility on methods and properties (although through the # prefix, which still breaks my heart). I’m assuming the next logical step will be adding protected visibility, however, right now it’s missing and I think all three are needed if you want to have a proper “OOP experience”. Protected properties and methods can be accessed only from within the class or one of its children (as opposed to private visibility, which limits access to only the parent class).

I’ve always struggled to call JS an OOP language, and until I see a way of dealing with the internals of classes without having to reference the prototype chain, I’ll keep struggling. Why couldn’t they just keep working on extending the prototypal inheritance model instead of giving us this cheap version of classes? That’s a question for the ages.

Right now, I’ll just say “thanks” for the syntactic sugar added and I’ll keep an eye out for new OOP-based features in the future.

But what about you? What’s OOP concept are you missing from JS that I haven’t mentioned yet? Or even better, out of the ones I’ve mentioned, which one is the one you want the most? Leave a comment below!

Tip: Share your reusable components between projects using Bit (Github).

Bit makes it simple to share, document, and reuse independent components between projects. Use it to maximize code reuse, keep a consistent design, collaborate as a team, speed delivery, and build apps that scale.

Bit supports Node, TypeScript, React, Vue, Angular, and more.

Exploring shaed components on Bit.dev

--

--

I write about technology, freelancing and more. Check out my FREE newsletter if you’re into Software Development: https://fernandodoglio.substack.com/