Please stop using classes in JavaScript

For years, OOP (object-oriented programming) was the de-facto standard in software engineering. The concepts of classes, polymorphism, inheritance, and incapsulation dominated and revolutionized the development process. But everything has an expiration date, programming paradigms included. In this article I will talk about why were classes introduced in the first place, why it is a bad idea to use classes in JavaScript, and what are some of the alternatives.

I am not going to talk about why OOP is fading away in general, but you can check out this great article for more info.

Pre-ES6 classes

Even though the class keyword was added to JavaScript since ES6 (ECMAScript 2015), people were using classes earlier. The way to achieve this was constructor functions and prototype delegation. To show you exactly what I mean, I am going to implement the same class in ES5 and ES6 environments. Consider a class Car and SportsCar that inherits Car. Both of them have make and model properties and start method, but SportsCar also has the turbocharged property and overrides the start method:

As you probably guessed, the Car (line 2) and SportsCar (line 18) functions are constructor functions. The properties are defined using this keyword and the objects themselves are created with new. If you are not familiar with prototype, this is a special property that every JS object has to delegate common behavior. For example, the prototype for array objects has the functions you probably know well: map, forEach, find, etc. The prototype for strings has functions replace, substr, etc.

After the Car object is created on line 33, you can access its properties and methods. The call to start on line 34 results in the following actions:

  1. The JS engine asks the car object for a value with the key start.
  2. The object responds that it has no such value
  3. The JS engine asks the car.prototype object for a value with the key start.
  4. the car.prototype returns the start function, that the JS engine executes immediately.

Accessing the make and model properties are performed similarly, except they are defined on the car object directly, instead of the prototype.

Inheritance is a bit trickier. It is handled on lines 24-25. The most important function here is the Object.create function. It accepts an object and returns a brand new one, with its prototype set to whatever was passed as an argument. Now, if the JS engine does not find a value on the sportsCar object or sportsCar.prototype, it will consult sportsCar.prototype.prototype which is the prototype of the Car object.

ES6 Class keyword

With the release of ES6 in 2015, the long-awaited class keyword arrived in JavaScript. It was done as per numerous requests by the community because people were feeling uncomfortable coming from object-oriented languages. But they missed one important point.

JavaScript has no idea what classes are

JavaScript is not an object-oriented language, it was not designed to be one, the notion of classes is absolutely not applicable to it. While everything in JS is indeed an object, these objects are different from the ones in Java or C#. In JS, an object is simply a Map data structure with a somewhat sophisticated lookup procedure. That is it, really. And when I say everything is an object, I mean it: even functions are objects. You can check it with this snippet:

Ok, this is all good, but how does the class keyword work then? Glad you asked. Do you remember the Car and SportsCar example earlier? Well, the class keyword is simply syntactic sugar on top of that. In other words, class produces conceptually the same code and serves only aesthetic and readability purposes. As I promised earlier, here is an example of these same classes in ES6:

These examples are identical and produce the same result. What is interesting, they produce (almost) the same code under the hood. I will not write it out here, but if you are curious, head out to the online Babel transpiler and have a look at the output.

Why not?

Now you should have an understanding of what classes in JS are and how they work. Now, with all this knowledge, I can explain why using classes in JS is a bad idea.

  1. Binding issues. As class constructor functions deal closely with this keyword, it can introduce potential binding issues, especially if you try to pass your class method as a callback to an external routine (hello, React devs 👋)
  2. Performance issues. Because of classes’ implementation, they are notoriously difficult to optimize at runtime. While we enjoy performant machines at the moment, the fact that Moore’s law is fading away can change all that.
  3. Private variables. One of the great advantages and the main reasons for classes in the first place, private variables, is just non-existent in JS.
  4. Strict hierarchies. Classes introduce a straight top-to-bottom order and make changes harder to implement, which is unacceptable in most JS applications.
  5. Because the React team tells you not to. While they did not explicitly deprecate the class-based components yet, they are likely to in the near future.

All of these issues can be mitigated with JS objects and prototype delegation. JS offers so much more that classes can ever do, yet most developers are blind to it. If you want to truly master JS, you need to embrace its philosophy and move away from dogmatic class-based thinking.

Get new content delivered to your mailbox:


  1. my god | may 14, 2020

    you have to be 16 to still fall for this “such and such technique/methodology/language is dying” specially with our long, long , looong history of how freaking difficult it is to kill anything in computing… hell we had to make a fucking decades old campaing to kill IE, and there’s still people who have to deal with it today (and no they don’t have a choice).

    Just stop prefacing every good article you write with some futurology bs, you don’t have to/ can’t predict how the whole world will behave based only on whats on your own backpack

    • michael krasnov | may 15, 2020

      Chill, dude. I am merely expressing my personal opinion on how quality JS code should look like, and certainly not trying to bury OOP completely.

  2. nic | may 18, 2020

    Very nice article. Unfortunately JavaScript suffers from being mainstream language, and they are adding a lot of syntax sugar (or garbage) in order to conform to existing paradigms. That’s all about people are not willing to learn the language in depth, companies are not willing to pay for educating their employees, etc. It’s pity because many don’t use the real power of JS because of this, that can enable writing simple and efficient code.

  3. eric cavazos | july 1, 2020

    I agree with you and it’s sad that because of the influence of other languages, classes have been targeted as the way to do things, but not needed. I think this stems from Javascript becoming so popular and developers from languages such as Java coming in with a heavy-handed influence. unfortunately.

    I worked on a large codebase that had classes for an API and we constantly had memory issues with Nodejs using classes. We took on an undertaking of removing and not using classes, but taking a more functional approach and the memory saving was more than 82%

  4. grey himmel | august 22, 2020

    Hi! I’d like to point out that something in this article is very misleading. You mention that React might be removing class support in the near future, in point number 5.
    While yes, React does mention that classes can be confusing and that there are several advantages to using hooks over classes, they also explicitly state that they don’t plan to remove class-based component support “for the foreseeable future.” This is stated multiple times in the page linked there. It might be good to read a source thoroughly before citing it in the future!

    • michael krasnov | august 22, 2020

      I read this documentation, thank you very much. Of course, react team cannot do this in the foreseeable future, but this does not cancel the fact that they (1) want to and (2) they can’t yet because of us

  5. I disagree. Readability and clarity counts, and it counts a lot, which is why I think the class syntax should be used when appropriate. To respond to your criticism of classes and why not to use them:

    1. The binding issue, I agree, is an annoying one. I prefer the Python way of automatically binding functions to instances. But this is not a reason enough in itself to never utilize the class keyword.
    2. The performance of it is just not a problem (premature optimization is the root of all evil).
    3. Not having private variables is a non-issue (Python has been doing just fine without them for a very long time).
    4. “Strict hierarchies” is not mandated. You can design and use classes without strict or deep hierarchies. I personally recommend not going too deep into inheritance. It makes code more complex to comprehend.
    5. React team recommends hooks, because learning how “this” and binding works is difficult for beginners. And I agree. Hooks also give some other nice features classes don’t have. But if you understand how classes work, feel free to use them, if it is the proper tool for the occasion.

    “If you want to truly master JS, you need to embrace its philosophy and move away from dogmatic class-based thinking.” I say, move away from dogmatic bandwagoning and mindset of absolute rejection of tools. Classes are a tool. You can use the tool when you feel it is the proper way to solve a problem. For some, it’s good, for others, there are better options. I strongly disagree with your dogmatic ideology of classes always being bad, and I hope the readers of this article won’t join the bandwagon.

  6. Agree with ak’s comment 1000%.

  7. nik po | january 14, 2021

    I completely agree, classes should no have been introduced. React is regretting it. So much unreadble code. Just see what poor babel has to do.

  8. There is absolutely no need for the Class abstraction in JS. It hides the real thing and the capabilities with what you can do with simple prototypical approach. Stay with the good old `new` keywrod.

  9. ravishankar haranath | march 3, 2021

    Completely agree to your views! The “object” of JS shouldn’t be seen in the light of OOPs in the first place. Moreover, many languages including Java/C# are putting various functional stuff to capture the developers in that segment and so are languages like JS/TS doing the reverse (i.e., trying to capture the OOPs market). I would rather be happy if the the so called “class” syntactic sugar has been introduced in a different way (may be, calling it something else) so that, it just gave a easy wrapper to define all those prototypical mappings, that would have been good enough.

    Anyways, as many of the readers commented, it’s the companies, the industry’s influence which takes precedence over the pure advocacy of a developer :-).

  10. louiszen | march 10, 2021

    Stupid is not the class support in JS but the people who use classes in a wrong adoption in OO Design.
    You must have a “just to enough” mindset in designing class components which normal programmers wont have.

    Stop using Dogs-Animal like sample to show the complexity of class. There are programmers which can use classes well in readability and computing resource management. I can tell that the concept of OO learn from university classes is stupid, but class itself is not.

    Class is a concept that simulates the objects in our real world, if you refuse it, it is contradict to the fundamental direction of programming itself.

  11. sam elsamman | april 24, 2021

    OK so you don’t like classes. Everyone is entitled to their opinion. You list six reasons why and then say “All of these issues can be mitigated with JS objects and prototype delegation. ” I am not clear that all six of these issues are mitigated through prototypal delegation.

    1 – Binding issues: Yep as AK pointed out a pain point for sure but this is inherent in any object that has functions so is also true of prototypal delegation

    2 – Performance issues: If you create objects from templates and change only a few properties than prototypal delegation (Object.create) is certainly more storage friendly since storage for properties is only allocated when you modify the properties and the rest freeload from the template. If most of your instantiations have unique props then that benefit diminishes.

    3 – Private variables: Yes they would be helpful and still at stage 3 in TC39 though they are widely used in Typescript. I don’t know that they are the “main” reason for using classes and besides you don’t get them with prototypal delegation. You have to use a factory pattern with closures to get them.

    4 – Strict hierarchies – That is a design issue and would be the same issue with prototypal delegation.

    5 – React – Yes react went to functions which are just a more convenient and concise way to create components (once you wrap your mind around useEffect). Their reference to classes is in the context of creating components and not, as I understand it, a condemnation of classes as a language feature. Obviously classes don’t play well with Redux so most React apps don’t make much use of classes.

    I wrote a blog article many years ago about why I would not use prototypical inheritance. My beef with it was that it had aspects that could confuse people. Take this example:

    const proto = { name: “”, siblings: [ ] }

    You are an experienced Javascript programmer and know full well that 2 will be logged. How do we explain that to someone just starting out?

    The point I am working myself up to is that I was wrong to condemn prototypal delegation. It is a language feature and a very useful one. Classes, to my way of thinking, are also useful and have their place. Yes they can be misused and if you come to Javascript from a hardcore Java way of thinking with all sorts of highly abstract base classes then yes maybe you are fighting the currents.

    I use classes in many situations because I like the clean syntax, the measure of flexibility with object references (like the array example above) and frankly because I grew up with them and they seem natural and readable to me. I only use them in contexts where the extra storage is immaterial to the application and I avoid inheritance except when it models real-world relationships.

    I also use prototypal delegation. In my view Javascript has no bad tools, just opportunities to use the tools badly. My two cents.

  12. gaurav | may 3, 2021

    As far as private variables are concerned, you can use them by using the # prefix. babel and chrome support it, though it is still a proposal I think.

  13. I’ll stick to classes, but thank you.

  14. bhagya | june 19, 2021

    I noticed something strange though. I am very new to JS yet. why is ‘function’ keyword not allowed/ not needed in a JS class? I am curious. Please shed some light?

    • michael krasnov | june 25, 2021

      It’s just the way syntax was decided, no particular reason

  15. awdrifter | july 6, 2021

    BRZ is naturally aspirated, not turbocharged.

    • michael krasnov | july 6, 2021

      Anything is turbocharged if you turbocharged it

  16. dan | july 9, 2021

    TLDR, thanks for your complaint, now provide something helpful.

    Class based OO doesn’t have an expiration date, so don’t speak for engineering because you don’t like how imperative programmers write their javascript code. I agree that classes are not befitting of Javascript’s design, as JS is a functional language, that’s make sense.

    So you’ve registered your complaint, and explained why it’s bad (sort of), but provided no guidance for people who come from imperative languages outside of DON’T DO THAT. So this article is pretty much just a hater ranting and not providing anything useful for the world.

    It would be great to see suggestions and some refactored code in your example to how you would write it in Vanilla JS (not React). Then explain that most javascript snobs (even good ones) can’t agree on how to organize their client-side code once it starts to get big and should just use on something documented like Vue, React or Svelte so other devs to hate them.

    I switched to node on the back end about a year ago and while I understand its benefits, I feel imperative programming is a better developer experience, and a more welcoming design for the majority of developers. Also, idgaf about the scaling argument or my bundle being a few extra kilobytes, great developer experiences trump infinite scale (unless you’re a part of that smaller group where scale is paramount).

  17. i just programing applicatins in java before and i suprised when see how trash is js classes.they just build useless.i dont know if you feel it or not.

  18. from your deleted constructive criticism. | july 14, 2021

    Thanks for deleting that last thoughtful post of mine. Shameful waste of time on my part. If you only accept posts from people who agree with you, why didn’t you say so? It would have saved us both time.

    I look forward to watching JS evolve over the next 3-5 years or months and future contradictory blog posts as you change your personal preferences. Why don’t you and others agree adapting imperative features in your JS is beneficial for the developer experience and ecosystem and figure out out to make it performant. After all, don’t we all want to work less and be more productive? Why do you think await exists? Did you write JS before it existed?

  19. antoine | july 31, 2021

    there is an error in your article: you said
    “Now, if the JS engine does not find a value on the sportsCar object or sportsCar.prototype, it will consult sportsCar.prototype.prototype which is the prototype of the Car object.”

    sportsCar.prototype.prototype is undefined, it should be : sportsCar.prototype.__proto__

  20. antoine | august 4, 2021

    1) erratum from my last post, it should be:
    “Now, if the JS engine does not find a value on the sportsCar object or sportsCar.__proto__, it will consult sportsCar.__proto__.__proto__ which is the prototype of the Car function.”

    also line 35 should be: console.log(sportsCar.turbocharged); // true

    and finally, you could replace the two lines
    SportsCar.prototype = Object.create(Car.prototype);
    SportsCar.prototype.constructor = SportsCar;

    with a unique line:

  21. trapcode | august 12, 2021

    In my opinion.. this blog post is misleading and sound like an opinion of someone inexperienced.

    I have been using classes and objects, both have use cases and No I don’t see a performance downtime.

    These days everyone blogs for attention and not facts. It’s sad!

leave a comment