DEV Community

Discussion on: The class Boogeyman in JavaScript

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.