DEV Community

Cover image for Do we really need classes in JavaScript after all?

Do we really need classes in JavaScript after all?

Dominik Lubański on December 11, 2018

Among a lot of other great features, ES2015 introduced the class syntax. For some, it was a missing piece in the object-oriented programming; for o...
Collapse
 
akashkava profile image
Akash Kava

Coding consists of two major parts, one logic and one is organizing logic. Consider logic as a contents of book and organizing as a book library.Book Library is organized by categories and then it is further organized by either author name or title in dictionary form. Imagine if you had a good contents of book but if it wasn't organized properly. Imagine if everyone organize contents of book and book in library with random order.

I consider class as a way to organize logic, you still have your functional ways to write logic but class is well understood by everyone and it is easy to document and organize. And it is very easy to refactor the code because IDE knows all references of identifier and it can safely refactor it. This was basically the reason why C++, Java and C# became more popular because developers need not focus on how to write it correctly and were able to focus on business needs.

Collapse
 
smalluban profile image
Dominik Lubański

This is an excellent explained opinion with an example :)

The class syntax is a natural way to express objects form a real world. They represent something, which can have unique properties attached. The problem is that we are using classes to do everything, and we mix business logic with the state. We do that because it is so easy. Only what we have to do is add methods...

it is very easy to refactor the code because IDE knows all references of identifier and it can safely refactor it

IDEs can also handle more functional approach. If not, they will. If it would be opposite, I would be very sorry for all functional languages programmers.

Collapse
 
akashkava profile image
Akash Kava

IDEs do handle refactor in functional language, but it will not be as powerful as the one with class language.

You are right about doing everything in class, infact same applies to functional, people want to do everything in functional way, that is also wrong, using best of both worlds will be perfect approach.

Collapse
 
wiredferret profile image
Heidi Waterhouse

That’s a useful analogy, thank you!

Collapse
 
wuz profile image
Conlin Durbin

I quite dislike classes in JS - I put together some of my thoughts on it here: MarxistJS. Basically, my problem with them is that they add a lot of problematic mental models for a new JS developer.

If you are coming from another programming language, you might expect classes to work the same way you are used to - which in many ways they do. But JS doesn't have real classical inheritance since it is a prototypical language. Using a standard function+object+prototype chain "classes" is a good way to learn how JS works, but hiding all that behind the class sugar is too much abstraction to me.

I feel like the addition of classes in JS was done to appease a very vocal minority and didn't take the consideration of what JS actually is.

Collapse
 
smalluban profile image
Dominik Lubański

I can't agree more. One of the more general problems of classes is that they are not what they seem to be if you came from other languages. Prototypical inheritance is much different from the classical approach to classes.

Collapse
 
tomekbuszewski profile image
Tomasz Buszewski

Hello Dominik ;)

I like classes in general, but I feel that the JavaScript implementation isn't mature enough. And with this new proposals (ridiculous #, for example), we aren't getting any better. This was one of the reasons I switched to TypeScript for my larger things. Interfaces, private/protected/public methods, all seems very in-place.

I completely understand your lack of sympathy towards extending, inheriting etc., but this comes with the OO design. If you create a class, you have to bear in mind that it may be extended by some other entity. And what happens next is the responsibility of one doing the extension. If this person overwrite your method, well, perhaps she or he should look at the base class first?

Another fact is, I tend to steer towards functional paradigm whenever I can. But the problem with this approach is, you will need some state control, sooner or later. They, you'll create more and more abstract entities only to store something that a class instance could easily contain. While this isn't always bad, it often introduces higher complexity which, in result, may yield harder maintenance.

To what this boils down to? I would say that using paradigms where they apply.

Collapse
 
smalluban profile image
Dominik Lubański

Thank you for your comment :) I can't resist showing you an interesting example. It is about one of your sentences:

If this person overwrites your method, well, perhaps she or he should look at the base class first?

Are you sure, that people are using inheritance in the right way? Below example is from one of web component implementation (here you have full source code):

class GridElement extends
      Vaadin.ElementMixin(
        Vaadin.ThemableMixin(
          Vaadin.Grid.DataProviderMixin(
            Vaadin.Grid.ArrayDataProviderMixin(
              Vaadin.Grid.DynamicColumnsMixin(
                Vaadin.Grid.ActiveItemMixin(
                  Vaadin.Grid.ScrollMixin(
                    Vaadin.Grid.SelectionMixin(
                      Vaadin.Grid.SortMixin(
                        Vaadin.Grid.RowDetailsMixin(
                          Vaadin.Grid.KeyboardNavigationMixin(
                            Vaadin.Grid.A11yMixin(
                              Vaadin.Grid.FilterMixin(
                                Vaadin.Grid.ColumnReorderingMixin(
                                  Vaadin.Grid.ColumnResizingMixin(
                                    Vaadin.Grid.EventContextMixin(
                                      Vaadin.Grid.StylingMixin(
                                        Vaadin.Grid.ScrollerElement))))))))))))))))) {
Enter fullscreen mode Exit fullscreen mode

You still think that a user of GridElement class knows every single property and method, that all of this dependencies add?

Collapse
 
tomekbuszewski profile image
Tomasz Buszewski

Are you sure you want to use Vaadin as an example for anything? :D

This code, while very extreme, shows the difference between knowing the syntax and knowing how to program. While still valid, creating such structure introduces almost impossible way of telling what is being used, overwritten etc.

Thread Thread
 
smalluban profile image
Dominik Lubański

This is one of many examples, that look like this in the web components area. Paper elements from the Polymer team are not much better in this :)

Thread Thread
 
tomekbuszewski profile image
Tomasz Buszewski

I see, but this proves nothing. Saying that "there are many examples of bad practices" can be revoked with "there are many examples of good practices". You don't stretch a rubber band the the max just because it can be stretched :)

Collapse
 
panta82 profile image
panta82

Main benefit I get out of ES6 classes is defining the shape of data I am dealing with, so I can talk and think about it in precise terms. When I say "Customer", I know exactly what fields and properties that entails (and IDE will help me remember it too).

Member functions and inheritence are less useful for the reasons you stated in your article. Any kind of business code I prefer to keep in pure functions or service objects, that are given class based objects to manipulate. Code and data kept mostly separate.

Mixins or composition patterns like yours don't really do much for me, as they muddy the waters of what each thing is and what can be done with it.

Collapse
 
smalluban profile image
Dominik Lubański

I like your approach. Classes are definitely good at creating data structures. Business logic in JavaScript can be tricky in class syntax (how I tried to point it out in the article).

Mixins or composition patterns like yours don't really do much for me, as they muddy the waters of what each thing is and what can be done with it.

The ideas behind hybrids library might be more clear to you if you look at the project documentation (especially Core Concepts section). I didn't want to mix subjects in this article and make it too long. In next weeks you can expect posts about those concepts on dev.to :)

Collapse
 
smalluban profile image
Dominik Lubański

Of course, I remember definitions on prototypes. But then, I didn't understand very well what's was going on with them. Classes made this simpler and cleaner. Also, they introduced own problems.

The side effect of the SimpleCounter is outside of the definition in purpose. It is private, so users can't trigger it accidentally. It might be strange at first, but it has own sense.

This concept is also great for testing. As you can see, we can export side effects, and create unit tests for them without component initialization. They are just simple functions.

I am not sure what it would look like completely, but this is a great start.

This is exactly what I want, a discussion about better web development. And I will be my success if I encourage someone to create next great ideas.

Collapse
 
ben profile image
Ben Halpern

Would it be fair to say that this conversation is fairly steeped in front-end web development?

How might you spin this conversation when other present or hypothetical use cases are accounted for more centrally?

The issues with scope and confusion would still be present, but might classes be more worth it in different contexts?

Collapse
 
joelnet profile image
JavaScript Joel

Would it be fair to say that this conversation is fairly steeped in front-end web development?

I think the examples used are very front-end. But I think that is because that is the larger audience. But I believe these concepts apply equally to node development as well.

Developers that come from other OO languages, reach for classes first due to familiarity with them. But JavaScript classes do not behave like those other languages, so people get easily tripped up.

JavaScript classes have their quirks due to the complexity of having to retain backward compatibility. JavaScript class Inheritance is mocked, but underneath (and hidden), it's still using prototypal inheritance.

And due to these expectations, it's my opinion that's where a lot of frustration comes in.

I am not a fan of JavaScript classes. To use them properly, you should understand how they are making prototypal inheritance. So you need to understand both anyway.

JavaScript's prototypal inheritance is exposed when you run into code like this:

class Bork {
  constructor() {
    this.message = 'Bork!'
  }
  bork() {
    return this.message
  }
}

const bork = new Bork()
const borkBork = bork.bork

bork.bork() //=> "Bork!"
borkBork() //=> Error("Cannot read property 'message' of undefined")

It is commonly found in React with something like this:

render() {
  // potential bug
  return <button onClick={this.handler} />
}

We have so many workarounds because we have an imperfect solution, the JavaScript class.

IMO, JavaScript classes were a mistake and they lead to much unnecessary confusion. They don't provide anything additional or extra and there are better ways of writing code.

This code is a good example of that as you will not run into any of the pitfalls of this.

Cheers!

Collapse
 
smalluban profile image
Dominik Lubański

Yes, my concepts were created in the context of web development. I was looking for solutions, which can make creating web components simpler and less confusing. Initially, I wasn't thinking about more general problems. I can't say certainly, that those ideas will be the best option in other contexts. However, I am sure, that is worth to try.

Described classes pitfalls are general. You have to deal with them regardless of what you create, next controller in your node.js application or component in your favorite framework. That is why I put an open question about JavaScript, not only in the web development context.

How might you spin this conversation when other present or hypothetical use cases are accounted for more centrally?

The first idea, which I would recommend to test is the property descriptor concept. It allows switching class definition to a plain object. What can we get in return? Possibility to test parts of the definition, share individual properties between definitions, using pure functions and many other.

Collapse
 
kayis profile image
K

While I like classes less and less, I think their addition to JS was a good thing.

Before them, I worked with projects that had >3 different class implementations in them, all with their own ups and downs.

Now everyone tends to use the ES2015 version and things are much clearer.

When everyone uses one class implementation, we can also learn more from each other. If someone gets rid of classes in one library, others could maybe use some of the approaches to get rid of them in their implementations too.

Collapse
 
smalluban profile image
Dominik Lubański

Using raw function constructors and prototypes was for sure complex and verbose. That advantage of the class syntax is not questionable. Unification is also a good thing. But, what do you think about next additions to this syntax, like class fields, private fields - in my opinion, it is a try to make classes more complex and less straightforward. If I create a private method, can I send it outside of the class definition? Another example - using class fields for defining methods can make it not efficient.

If someone gets rid of classes in one library, others could maybe use some of the approaches to get rid of them in their implementations too.

Can you explain what you mean here? Not using classes don't have to mean to create not understandable API, which has to be changed.

Collapse
 
kayis profile image
K

I meant that if one library creator uses classes, and finds another elegant implementation that could be used instead, this approach could be adopted by other library creators more easily if they both used the same ES2015 class implementation.

But yeah, I think the ECMAScript people will just add to the class so Java/C# people will be satisfied...

Collapse
 
abhinav1217 profile image
Abhinav Kulshreshtha • Edited

As a php developer, who use js for front-end only, Classes didn't benefit me much. I already used OO-Js by extending proto, and always had a namespace for my script.

On flipside, recently, I have used typescript to generate said front-end script, And classes makes organization better. Compiled ecma-5 code does contain extra junk than what I would have normally written, but it's a tradeoff I can accept.

Now, as a node developer who work on back-end, Classes have made my life easier, I can work with normal OOPs mindset, Organize modules in a way that make sense. Classes makes js feel like a proper programming language. Again, Typescript makes working on it better. If you remember time before typescript, code organization was messy.

So in summery, classes are surely important addition to language. What is hard is that our mindset still sees js as a scripting language, and with that, classes feels like an unnecessary complication. So a noob mindhack I used was to tell myself that js is a scripting language and TS is a compiled OOP language. That cleaned up my itchy coding.

Collapse
 
chenge profile image
chenge

Erlang's father Armstrong has a post say "Object is wrong".

Golang has OOP but no inheritance.

Elixir uses a functional way.

So in JS we can use class, but we should just use class as interface and no data inheritance like golang.

Collapse
 
patarapolw profile image
Pacharapol Withayasakpunt • Edited

My thought is there can even be object syntactic sugar as well. (Just like in Kotlin.) It makes easier to work with typings in TypeScript.

I don't particularly hate this, BTW.

Collapse
 
renannobile profile image
Renan Lourençoni Nobile

As a JS developer I can say that JS classes have a way to go. Binding context is a real pain in the ass.

Hybrids looks incredible, I'll be giving it a try.

Thanks

Collapse
 
smalluban profile image
Dominik Lubański

Thanks for the nice words about the library. Stay tuned for the articles on dev.to about the concepts :)

Collapse
 
lysofdev profile image
Esteban Hernández

I'd say classes are significantly more useful in a Typescript environment.

Collapse
 
sylwesterdigital profile image
Sylwester Mielniczuk

Making things overcomplicated is the way to discriminate those who are not masochists.

Collapse
 
yorodm profile image
Yoandy Rodriguez Martinez

Is this the "objects are the poor man's lambda" debate of our times?