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:

77 comments

  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.

    https://babeljs.io/en/repl#?browsers=defaults%2C%20not%20ie%2011%2C%20not%20ie_mob%2011&build=&builtIns=false&spec=false&loose=false&code_lz=MYGwhgzhAEDKwCcCWAHALtA3gKGggrgHYAUAlDtgJAC-021QA&debug=false&forceAllTransforms=false&shippedProposals=false&circleciRepo=&evaluate=false&fileSize=false&timeTravel=false&sourceType=module&lineWrap=true&presets=env%2Ces2015&prettier=false&targets=&version=7.12.12&externalPlugins=

  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: [ ] }
    f1=Object.create(proto);
    f2=Object.create(proto);
    f1.siblings.push(“Sam”);
    f2.siblings.push(“Ashling”);
    console.log(f1.siblings.length);

    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:
    Object.setPrototypeOf(SportsCar.prototype,Car.prototype)

  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!

  22. Dude, looks like you don’t know much about OOP.
    OOP is for humans not for the compiler, it’s a paradigm to write and organize the code. Especially on a large scale. Good luck with those hooks and callbacks in JS.

  23. TL; DR: maintaining a typeless classless js would be a nightmare in medium sized real projects let alone huge ones

  24. bruxor | january 13, 2022

    While I agree that using classes are adding unnecessary complexity, I disagree with some the arguments given in the conclusion.

    1. Binding issues: yes, having to use the new keyword to bind this to the context of the class is already a first problem. This is pretty much the only one of your conclusions I fully agree with.
    2. Performance issues: do you have any benchmarks supporting that classes are significantly slower? If they’re really slower, by how much? We can’t just claim that something is slower without providing data supporting that claim.
    3. Private variables: what about prefixing class attributes with #: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Private_class_fields
    4. Strict hierarchies: It doesn’t have to be that way. It’s been years that the OOP world is moving away from inheritance to use composition instead. https://en.wikipedia.org/wiki/Composition_over_inheritance
    5. Because the React team tells you not to: We call that an argument from authority. https://en.wikipedia.org/wiki/Argument_from_authority
    The fact that the react team tells us no to use classes won’t tell us anything about why it is not a good idea to do so. They used to recommend classes, so few years ago you could have argued the exact opposite by saying “use OOP because the react team is telling you to use classes for the components”.

  25. new to js | january 21, 2022

    whats the alternative if we’re not using classes? Functions?

  26. norbert klar | february 2, 2022

    Javascript is a poorly designed language, so I take any syntactic sugar to make my life easier.

  27. bryan | april 1, 2022

    I am ignoring michael’s list of why he thinks the class keyword is bad in javascript.
    Why? Because they are unsubstantiated opinions which I have not found any supporting evidence online.
    React works fine with classes (though it is not straight forward as the function based approach).
    There is no performance nor memory issues with classes; they are statistically equivalent; no user detectable difference until you are up to the millions of objects.
    Private variables are nice; however, obscured public variables have the same result.

    Having said all that, javascript is not an OOP language and it is a mistake to think the class keyword has any relationship to Java / C#.
    As long as you understand a javascript class is a helper and not really that much different to a function, use whatever you like.
    After all if you are keen on the class keyword, and it did not exist, you would simply use the function closure from a class.

  28. I can’t believe what I just read! You must be 14 years old, copy&paste “software developer”!
    “JavaScript is not an object-oriented language, it was not designed to be one” LMAO!!!

    JavaScript is object oriented to the bone, everything in JavaScript is an object. You are confusing class based object oriented programming that came from C++, Java and other mainstream languages, and prototype based object oriented programming that is JavaScript.

    Saying how OOP has expiration date is just foolish. You are the reason JavaScript community sucks. Script kiddies that don’t understand basics of programming, but have strong opinions how “javascript was not designed to be oop” and how “oop is programming paradigm with expiration date”… you just blew my mind!

    JavaScript’s class and extend keywords don’t introduce class based oop into JavaScript, they are just syntactic sugar, underneath it’s still prototype based oop.

    Have fun copy & pasting, and building strong opinions you teach to others without knowing what you are talking about!

  29. 100% agree | june 4, 2022

    Javascript classes are just bloat and hides the beauty of js, which is its functional simplicity. You don’t even need prototypal inheritance or the ‘keyword’, you can literally and elegantly code everything using only functions and simple data structures. Absurdly enough, only very seasoned js developers understand this.

  30. Literally the best thing about JS is it’s diversity. Typescript and Class hierarchies are attempts to restrict that diversity of thought and practice. After a difficult few years transitioning from a music career to dev career I can personally attest that if you want to be creative , experience ‘flow’ and sit ‘in the pocket’ when coding, do not go feel intimidated by opinionated engineers – TS and OOPs and TDD are engineering tools. I would argue they need to be applied only if and when a healthy creative mind frame ( fast, intuitive, iterative ) has begun to yield and *might* require retrospective engineering to support (NOT lock) it’s creative vision.

  31. craig | june 29, 2022

    I didn’t want to use classes for some of the reasons stated here, but they’re actually much faster in some use cases (at least from my tests).

    If you want the following: inheritance/extending, getters/setters, and most important for this test – overiding getters/setters on sub classes, then you can’t beat classes in javascript. I’ve toyed around for ages with factory function+mixins, and prototypes. I don’t know what’s going on under the hood but there are huge penalty’s with non-class based patterns that allow for getter/setter overrides. Unless someone can show me a pattern that works… i’m running on the assumption that browsers have optimized classes in some special way when it comes to my use case.

  32. darktrick | november 26, 2022

    Your statement is wrong : “JavaScript is not an object-oriented language”
    Javascript *IS* object oriented.
    You actually prove that yourself: “While everything in JS is indeed an object” <- That is the definition of object oriented.

    What you actually probably want to say is "Javascript is not class oriented" (By the way, C++ for example is not an object oriented language, but a class oriented language)


    object orientation vs class orientation is basically like ++i and i++: Just because everyone is using something the wrong way does not make it right.

  33. nabil alsaiad | may 2, 2023

    As a C# programmer who didn’t know anything but OOP programming with game development JS was a fresh thing to have and the fantastic feeling of being able to declare variables and functions on the fly with no need to make a class hierarchy and so much coding only to run a simple function.

    Even though I’m used to OOP and I love working with it, having it in JS feels weird and wrong in my opinion, OOP is amazing, in C# and Java, but not in JS, I’ve been using much OOP, classes and types in my projects lately and it was a real headache.

    After so much JS programming and experimenting with many things I can say, for me at least, plain JS is the best JS (just remember to through a tsconfig file in the workspace for type checking and autocompletion :D).

  34. – JS has private.
    – It is just function constructor but written in a way that people are familiar with (it’s called prototype-based OOP).
    – Stop using Babel if you find issues with it. Just use a bundler like ESBuild.

  35. can I ask you something. Other than JavaScript or Python, what other language are you fluent or partially fluent in?

    • michael krasnov | october 22, 2023

      JS and python arey hobby/personal projects languages, at work I mostly code in Java, been doing it for about 5 years

  36. rafael | november 1, 2023

    and know we know that classes and general IT foundations should be avoided by HTML writers 😝

  37. markus | november 9, 2023

    As a programmer with decades of experience from both functional languages (like JS) and OOP-languages like C#, I think that the syntactic suger of classes in JS is a good thing and sometimes makes for a better developer experience.

    For me, the biggest reason not to use classes (or class-like hacks) in JS, which you do not mention, would be that it might have a significant impact on the bundle size as classes can’t be minimized in the same way as functions and variables outside classes. Depending on the size of the code base this can be a huge difference.

    For most scenarios, even if the difference is huge, I can still see that classes help keeping the code base more maintainable for the majority of devs. Most of the time this is more valuable.

    I think that just because JS was created with certain limits and does not mean that we should not allow it to evolve – I mean static typing is not a JS-thing but TypeScript is getting serious traction. It’s all about productivity, developer experience and minimizing errors. This is fine as long as the performance impacts and impact on bundle size is acceptable in the given scenario.

leave a comment