DEV Community

Cover image for Do you need classes in JS/TS?
András Tóth
András Tóth

Posted on • Updated on

Do you need classes in JS/TS?

If you are starting out as a developer, you might run into these conflicting schools of thought: should I write "functional style" with its "pure functions" or go with "object oriented classes"?

The answer would be really long and this is going to be just a quick tip.

Beforehand it is important to know that Javascript (and consequentially TypeScript) is neither functional nor an object oriented language. It has elements of both and it breaks important contracts of either. See the last paragraph: "Only for the curious!".

If you are going to have several similar objects that persist over time (i.e. you keep them around for a long time and you regularly) and have some form of state that you access a class is a really good choice. However if you just need to transform an object to another object a function is your best bet.

The symptoms of not needing a class

The feature a class is truly giving us is accessing this in any of the defined functions. When some or more of your class methods do not access this and only the parameters passed and they also return the result, then you will need a function. Even better if you can make the function pure (in other words none of the parameters passed in are mutated)...

The algorithm to refactor this

  1. Find a class method that do not access this. Extract it into a method and update the depending methods.
  2. Check the class again, if the changed methods no longer access this: move them out as well.
  3. If every method access this you have the real class that is actually managing its own state.

Only for the curious

The classic example of breaking the functional paradigm is that on an array .sort() method mutates the array, while .map() returns you a new array instance. This is inconsistent and creates regular problems.

On the other hand objects created from traditional classes "own" their own functions, while in Javascript you can pass the function of an object and lose its this. You can also bind a function to a totally different object. There is a lot of frustration voiced when this phenomenon dawns on a developer coming from real object oriented background.

Questions, mistakes or do you wish examples? Blogging and learning is a collaborative effort, I need your help to help you. 🤝 Let me know in the comments! Cheers!

Top comments (7)

 
fjones profile image
FJones

I agree with most of this (particularly the relative verbosity of class vs prototype), though I would argue that classes in JS are still the better way to do OOP. OOP isn't just about encapsulation, it's about polymorphism and data transmission just as well. All of those are certainly helped by a clear class structure over module-based encapsulation.

Thread Thread
 
peerreynders profile image
peerreynders • Edited

Prototype-based programming is all but gone, save for polyfills.

class keyword or not - the objects instantiated still rely on prototypal inheritance. And in performance conscious code bases constructor functions are still "assembled" - that way method implementations can be shared by otherwise unrelated constructor functions (see Preact).

class vs prototype

Class free OOP doesn't relate to implementing inheritance with prototypes. "OOP with functions" typically refers to a plain literal object holding references to functions that share data through the closure of the factory function that created them.

function createDog(name) {
  let hungry = false;
  return {
    get type() {
      return 'dog';
    },
    get name() {
      return name;
    },
    set name(n) {
      name = n;
    },
    get isHungry() {
      return hungry;
    },
    play() {
      hungry = true;
    },
    feed() {
      hungry = false;
    },
    makeSound() {
      alert(hungry ? 'groan....' : 'Woof woof.');
    },
  };
}
Enter fullscreen mode Exit fullscreen mode

OOP with functions in JavaScript
How to decide between classes v. closures in JavaScript.

classes in JS are still the better way to do OOP.

Keeping in mind that in JavaScript Classes are a template for creating objects - for the most part they are just a creational convenience (until more is needed) but they are not the only way to create objects in JavaScript; unlike in mainstream class-based object-oriented languages.

James Coplien
"How many of you do object-oriented programming? What language? Java is the only language in which you cannot do object-oriented programming. Huh? Other languages. Smalltalk - no. C# - no. Python - no. No. Any JavaScript programmers here? Here are my object-oriented programmers - they're writing objects - the rest of you are writing classes. "

it's about polymorphism

JavaScript has always achieved polymorphism through "duck typing" - no classes required. TypeScript's structural typing is an expression of that. Either a value satisfies an interface or type alias or it does not - no need to implement, inheritor extend anything.

clear class structure

More often than not I hear people complaining about brittle, deep, complex class hierarchies.

"Favor object composition over class inheritance"
Gamma, Erich et al. "Design Patterns Elements of Reusable Object-Oriented Software". Putting Resuse Mechanisms to Work, p.20, 1994

So a "clear class structure" doesn't seem to be a pit of success for OOD/P in practice.

Functional programming is certainly seeing a new renaissance in JS.

I think that is a red herring. I myself have described JavaScript as function-oriented but using an FP-flavoured expression-based (as opposed to statement-based) style leads more to value-oriented programming.

Collapse
 
pengeszikra profile image
Peter Vivo

Imho I prefer the functional programming over OOP.
Because

  • Each class function have dependency of whole class.
  • Harder to handle class before crated vs. variable before created.
  • Much simple to write a function than class.
  • don't need to worried about this
Collapse
 
fjones profile image
FJones

It depends very much on the programming paradigm you apply. Traditionally OOP applications benefit from classes in JS, but is that the kind of JS we want to write? Do we prefer functional programming, or do we want to go back to using the actual design of the language and relying on prototypes?

Functional programming is certainly seeing a new renaissance in JS, but rarely in the terms that are actually related to traditional functional programming (pure functions, higher-order-functions, declarative programming). Prototype-based programming is all but gone, save for polyfills. It's certainly an interesting development.

Collapse
 
latobibor profile image
András Tóth • Edited

Prototype-based programming is truly gone, I only realized it when I failed an interview question about prototypal inheritance. "Well" I said "I haven't written anything prototype related in the last 4 years."

Onto the other approaches: since the language was not designed for either, doing them as they were written requires ugly hacks and clunky solutions. For the love of god I despise for example when I see a trainwreck like myThing(354)('adf')((_, stuff) => stuff.process()). If you stick to the basic rule of being as clear as possible with the least amount of boilerplate you won't use anonymous function compositions nor you won't fire up a whole dependency injection system just you can mock two dependencies for a test.

Collapse
 
devfranpr profile image
DevFranPR
Collapse
 
devfranpr profile image
DevFranPR

I know you're going to react to this and I want to learn more.