DEV Community

Discussion on: The class Boogeyman in JavaScript

Collapse
 
bytebodger profile image
Adam Nathaniel Davis

Your article doesn't acknowledge that the introduction of the class keyword undermined the growing "Object Factory" movement in JS user land.

I wasn't aware of the "Object Factory movement in JS user land." But I can't really offer an apology here. The factory pattern can be extremely useful. But it can also be a complete PITA when it's shoehorned somewhere that it doesn't "fit". The factory pattern can be an extremely useful tool - or it can be a pointless abstraction that only complicates the solution.

Quotes or not, you are betraying your own bias here - that "Class-based Object Orientation" is the only "true" OO.

I fully understand that JS is - and has always been - deeply dependent upon objects. But when almost-anyone talks about "OOP", they are referring to concepts that don't actually exist in JS. Specifically, they're referring to class-based objects.

I fully agree/understand that JS has objects. That it's based on objects. But when most programmers talk about OOP, they're not talking about the idea that a language uses objects or is based on objects. They're talking about class-based object instantiation.

In JS there never was a "class construct"

Right. That's called prototypical inheritance.

that could be instantiated in a variety of ways - constructor functions only being one of them.

Umm... Not really. The whole basis of "prototypical inheritance" is that that there are no guidelines by which you create new objects. You can only create an object by copying another object. That's pretty much the definition of "prototypical inheritance".

So in JS class is just some mental model of how an object ought to behave (according to class-based conventions) but doesn't really enforce how any object instance will behave during its lifetime.

TRUE In JS, class is just an "example" of which object to use as the prototype.

JavaScript isn't a functional language. Functions as first-class citizens aren't enough to push it into that category.

I think you missed the point of that passage. I 200% agree that JS is NOT an FP language. That passage was supposed to be a quote of the arguments against the class keyword. If you think I'm making things up as I go along, take a look at my article about the BS of people who want to claim that JS is a FP language: dev.to/bytebodger/javascript-s-fun...

You are overgeneralizing here. You are talking about the "Sacred Order of React". The React community is known to be Gung Ho on arrow functions. In the wider JS community there are pockets that are pushing back against the overuse of arrow functions especially if it is primarily motivated by (developer) "aesthetics".

I hope we can "agree to disagree" on this one. I'll admit that arrow functions are particularly-loved within React. I will not admit that this love is somehow limited to React. When I look at Svelte, or Vue, or even (modern) Angular, I see no indication that love of arrow functions is, in any way, confined to React.

For more detail see Eric Elliot's JavaScript Factory Functions vs Constructor Functions vs Classes (2016).

I have massive respect for Eric Elliot's intellect and overall knowledge. That does not mean that I agree with all of his positions. In some cases, I think he's borderline-delusional. He's probably forgotten more about JS than I've ever learned. But that doesn't mean that all of his JS contentions are correct.

Why don't you just go out in public with a "why doesn't this stupid language have classes" poster? BTW that function creates a component, not a class.

I'm getting confused at this point. React has a construct called a "component". But that only exists in React terminology. React compiles down to JS. And JS has nothing called a "component".

And sorry, "Functional Component" is an oxymoron - "Components are objects".
However some components may only need a pure render function.

You can call it an oxymoron if you want, but the simple fact is that, in React, you can create a "component" (which does not actually exist in JS...) with a function or a class. So you can call it an oxymoron if you like, but the simple fact is that I can create a React component without ever using class and without ever explicitly creating an object.

Collapse
 
peerreynders profile image
peerreynders • Edited

it can be a pointless abstraction that only complicates the solution.

Strangely enough some people still find this confusing (I don't) and feel that it's necessary to enforce encapsulation of non-public details and not simply rely on developer discipline. The object factory accomplished that with ES5 features. If those are features you value then it isn't pointless. In some ways an object factory is just an extremely simple builder.

they're referring to class-based objects.

.. people who have been introduced to OOP via languages (Java, C#, etc.) that implement class-based object-orientation - it's a variation of Baby Duck Syndrome.

Teaching OO: Putting the Object back into OOD (2003)

Almost everyone who teaches object orientation uses the class as a fundamental building block. Such an approach misses the central point of object orientation: the objects themselves, and what they portend for flexibility and effective design. This weblog is a case study in teaching object orientation.

James Coplien doesn't make this claim on behalf of JavaScript but as the foundation to Data, Context and Interaction. His position is that that you can't practice "true" object-oriented programming in Java or C# because they deal with classes, not objects.
fulloo.info

The point is that the belief that object-orientation has to be class-based is narrow-minded. People unable or unwilling to transcend that aren't accepting JavaScript for what it is but are still wishing that it is something else they are already familiar with.

That's called prototypical inheritance.

Prototypical inheritance is about "implementation inheritance", not class. Classes don't exist to enable implementation inheritance. For example VB5 had classes and interface inheritance - but not implementation inheritance. In class-based languages an object instance is a member of a class (or in the case of C++ possibly multiple classes) - the object instance holds the data while the class holds the functions that can act as methods on that instance data.

When using initialization by literal notation the archetypical object instance holds its own references to the functions that may act as methods on it - there is no class construct holding the methods that may act on all the object instances the belong to the class. The methods from Object (which is another object) are acquired via implementation inheritance.

The language feature that comes closest to identifying a class is the constructor function.

Given that it is quite common to initialize objects with the literal notation and subsequently augment those objects with the helpers from Object the constructor can only tell you what the object was at the time of creation - right now it could be something entirely different.

You can only create an object by copying another object.

Using initialization by literal notation the object's constructor is simply Object - not very useful for "classification".

In JS, class is just an "example" of which object to use as the prototype.

It's a creational blueprint - after creation all bets are off.

I think you missed the point of that passage.

While I was aware of your position your followup was

OK, sure. I agree with that.

That in no way disagrees with the "As a functional language" bit.

So I was

  • Making your point for you.
  • Making clear that I don't see JS as a functional language (which doesn't limit the usefulness of some functional practices, like higher order functions).

I hope we can "agree to disagree" on this one.

Framework enthusiasts still don't equate to the entirety of the JS community.
In my experience some vocal framework enthusiasts belittle others favouring the traditional function style. Kyle Simpson just won't be kowtowed into shutting up.

You yourself seem to favour arrow functions. But as it has already been pointed to you, using arrow functions everywhere is a case of pessimizing prematurely.

It can also squander an opportunity to communicate intent to the reader:

class Counter extends Component {
  constructor(props) {
    super(props);
    this.state = { counter: 0 };
  }

  // Intent to use as an event listener/callback to this
  // particular instance: 
  // Use arrow function bound to the object instance
  //
  increment = _event => this.setState({ count: this.state.count + 1});

  // Intent to be only used as a public method;
  // i.e. there is no need to bind a separate function
  // to the instance, a method shared via prototype is good enough:
  // Use shorthand method syntax
  //
  render (){
    return (
    <div>
      <button onClick={this.increment}>add 1</button>
      <p>{this.state.count}</p>
    </div>
  );
}

Aside: Initializing state inside the constructor is consistent with the idea that state is non-public. Initializing it as a public property doesn't convey that intent.

Private fields (stage 3) won't help either as they are private to the class that defines them and therefore will not be available to subclasses.

This whole preference-based use of arrow function expressions over traditional functions just reinforces the notion that Programmers know the benefit of everything and the tradeoffs of nothing.

i.e. stop using arrow function expressions based on preference and just use them where it makes sense.

I have massive respect for Eric Elliot's intellect

I wasn't using Eric Elliot as an "appeal to authority". It was merely a reference to an illustration of the various object creation approaches. He had some good ideas back in "Programming JavaScript Applications" but has become a bid eccentric since he adopted React.

I'm getting confused at this point.

The point being that in those days React had a disdain for JavaScript not supporting classes right out of the box. Back then they were still obsessed with class-based OO because they liked that compositional model only to later flip to the functional compositional model - ignoring alternate compositional approaches that were already in use with ES5.

But that only exists in React terminology.

React Components, Elements, and Instances (2015)

There are:

  • React Components
  • React Component Instances
  • React Elements

There is no "React Class".

If createClass returns a React Component shouldn't it be called createComponent?
The documentation for React.createClass even stated:

Create a component given a specification.

.

the simple fact is that I can create a React component without ever using class and without ever explicitly creating an object.

The initial idea was that simple components only needed a render method to transform props to React elements. So implementing simple components as a single render (pure) function instead of a whole object made sense. At that point "Functional Component" meant "a function as a render-only component".

The current incarnation of functional components with hooks is an object in a functional straight jacket.

  • The more hooks you use the further your move away from a function "that does one job and does it well".
  • This is accomplished at the cost of additional runtime checks during each render pass - e.g. emulating componentDidMount, componentDidUpdate, and componentWillUnmount with useEffect requires checking of the dependency array - rather than just calling a dedicated function at the appropriate time.