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... [Read Full]
markdown guide
 

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.

 

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.

 

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.

 
 

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.

 

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.

 

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.

 

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))))))))))))))))) {

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

 

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.

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 :)

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 :)

 

Classes in JavaScript was a terrible idea. There are no blueprints in JS to represent true "classes", and hiding this to make devs from other ecosystems feel welcome, only serves to make things worse. 😭

 

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.

 

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.

 

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...

 

Even though javascript is a 'functional' language, I would bet that most javascript developers write OO code. If you remember the javascript prototype chaining we were doing a few years ago which mocked the class behavior, the class syntax was a natural next evolution in syntax. I don't think it hurt anything.

After looking at your example, I was a little confused about the decoupled increaseCount function. It looks like it should be a method that belongs to SimpleCounter. That was my natural reaction. But now after thinking about it, I think we could use a pure functional component library.

I am not sure what it would look like completely, but this is a great start. I would look into seeing if you make state it's own entity like react hooks did. But use curried functions like you would find in Ramda to make the mutations. Each state entity would basically have its value, but it returned a function that handled the next mutation.

 

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.

 

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?

 

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!

 

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.

 

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.

 

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 :)

 

This article does bring up an interesting point that I never really noticed before: I declare classes all the time in C# and other languages, but for Javascript, I’ve not once written my own class. I guess it’s because the way JS does it is so convoluted that it’s better in my case to just wing it.

 

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.

 

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

 

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

 

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

 

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

 

Didn’t get that vibe, personally. This isn’t saying the class model and OOP as a whole are bad, just that its hacky addition to JS is very unintuitive for beginners and people familiar with OOP alike because there’s so much quirky crap it does.

code of conduct - report abuse