Not Awesome: ES6 Classes
A curated list of resources on why ES6 (aka ES2015) classes are NOT awesome
Table of Contents
- ES6 Classes in React
- Don't Want to Use ES6 Classes in React?
- Addendum (About Functional Programming)
- People You Should Follow
- Contribution Guidelines
DISCLAIMER: This is an opinionated summary of the core points made throughout the linked content. I am only providing this as a convenience for people who requested it. If you're looking for technical depth, skip this section. Please, take the time to dive into the content before drawing any conclusions.
- The ES6 class syntax, constructors, the
- While prototypal inheritance is very powerful in its own right, it is important to know that there is a growing movement among developers, both within and outside of the JS community (Ex: Composition in Golang), to shift away from inheritance in favor of object composition.
- Whether you choose to use prototypal inheritance, composition, or some combination of the two, you should consider using factory functions, object literals, prototypes, Object.create(), Object.assign(), etc. while avoiding ES6 classes, constructors, and the
If a feature is sometimes dangerous, and there is a better option, then always use the better option. — Douglas Crockford
Articles & Blog Posts
- Class Teacher
- Composition Over Inheritance
- How to Fix the ES6
- Inside the Dev Team Death Spiral
- Introducing the Stamp Specification -- Move Over,
class: Composable Factory Functions Are Here
- JS Objects -- Part 1: Inherited a Mess
- JS Objects -- Part 2: Distractions
- JS Objects -- Part 3: De"construct"ion
- Prototypes Are Not Classes
- The Open Minded Explorer’s Guide to Object Composition
- Think Twice About ES6 Classes
- Web Reflection: [ES5] Classes As Descriptor Objects
- We Don’t Need a Standard for Single Inheritance. Single Inheritance Taxonomies Are an Anti-Pattern.
- Why Prototypal Inheritance Matters
- Design Patterns: Elements of Reusable Object-Oriented Software
- Professor Frisby's Mostly Adequate Guide to Functional Programming
- You Don't Know JS
- Ashley Williams: If You Wish to Learn ES6/2015 From Scratch, You Must First Invent the Universe
- Composition Over Inheritance
- Douglas Crockford: The Better Parts - JSConfUY 2014
- Fluent 2013 - Eric Elliott, "Classical Inheritance is Obsolete: How to Think in Prototypal OO"
- Nordic.js 2014 • Douglas Crockford - The Better Parts
- Source Decoded: Composition vs. Inheritance
ES6 Classes in React
A Reasonable, Limited Approach to Using ES6 Class Syntax in React
I'm not convinced that using ES6 class syntax in this fashion is the best long term solution for React, and you should be aware of the alternatives: React.createClass(), react-stamp, and pure (stateless) functions. However, Dan has established a solid, reasonable set of guidelines to follow in the meantime. So, if you must use ES6 classes in React, please follow his lead:
- Resist making classes your public API.
- Don’t inherit more than once.
- Don’t expect people to use your classes.
- Learn functional programming.
- You can use class in your JS if you don’t inherit twice and don’t use super.
- Prefer to write React components as pure functions when possible.
- Use ES6 classes for components if you need the state or lifecycle hooks.
- In this case, you may only extend React.Component directly.
- Give your feedback to the React team on the functional state proposals.
With that said, we should think about why needing to use
extends in such a limited fashion, to establish sane & maintainable practices for the specific purpose of creating a React Component (through 1-level deep inheritance), is necessary in the first place. It probably means that there should be a better solution and/or a better syntactical approach to solving this problem. I’d like to see a syntax focusing on what the conceptual thing actually is, i.e., a component, not a class… Why was createClass() not originally named createComponent()? Why do we think that classes are the right tool for modeling components in the first place?
Also, read Dan's previous article on composition:
Don't Want to Use ES6 Classes in React?
Currently, it is not all that practical to completely avoid using ES6 classes in React due to the fact that functional components lack the lifecycle methods of ES6 class components (or the deprecated
createClass factory function). However, it is possible to avoid them by using Andrew Clark's recompose, a React utility belt for function components and higher-order components. Using recompose, you are able to use methods like
shouldComponentUpdate, etc. with functional components via the
lifecycle helper utility. However,
lifecycle currently uses React's
createClass under the hood, and many of recompose's other API methods are implemented using classes... So, you will probably still be using them if you use recompose in your project, depending on the specific methods you are using. However, they will be abstracted away from the code you are writing, which you might still find nice enough to consider.
Otherwise, if you are willing to abandon React compatibility & a React-like API altogether, look into snabbdom, a virtual DOM library focused on simplicity, modularity, & performance. Like Inferno, Snabbdom is extremely fast and features a powerful hooks API. Also, if you are a fan of JSX, you can keep using it via snabbdom-jsx. You may be surprised how similar what you can accomplish when using a minimal virtual DOM library is to when using a larger view library like React, especially if you are already heavily using a state container like Redux.
Addendum (About Functional Programming)
Since writing this not-awesome-list I've really jumped into learning functional programming core concepts/principles, and, honestly, I don't really use prototypal inheritance or object composition anymore either, because I really believe FP is the way to go. However, I do still think that if you're going to do OOP in JS, then using prototypes & the OLOO (Objects Linked to Other Objects) concept + object composition is a much better idea than emulating Java with class syntax, the constructor pattern, & inheritance. Embrace simple! OO composition is better than classical inheritance by a long shot, but functional composition is even better.
HOWEVER, I am mostly referring to application code when I suggest embracing simplicity by avoiding classes and OOP. I'm not saying that you should NEVER use ES6 classes or that there aren't any good use cases for them. The nature of V8 and other JS engines is that object-oriented code can often be better optimized. So, it's perfectly acceptable to use classes and an OO style to squeeze out as much performance as possible when writing the internals of a library. You have a good reason to do so in that case, BUT you can abstract away those details and make it so that the library's public API (and your application code when using said library) can be elegant and declarative. This is important for maintainability. Rigorous, consistent functional code lends itself to better understanding, and, thus, better long term maintainability. If micro-optimizations must be done in libraries for performance reasons, then so be it, but the power of abstraction allows you to hide imperative and/or OO code away from the user, saving them the headache of having to break out of a functional coding style in their apps.
I have also seen a number of people choosing to use ES6 classes as an abstraction to implement Algebraic Data Type libraries, and I understand why they do. It does seem like a logical choice when building out the methods of each data type to satisfy the various laws involved that define these algebraic structures. However, some of these libraries will provide a functional API via wrapper functions and not publicly expose each data structure's methods directly. I strongly prefer libraries that do this, or at least make the functional API variants ALSO available along with the method-based API, because it allows taking advantage of further FP techniques, like currying & partial application, which is very important for creating reusable functions.
People You Should Follow
The People Who Initially Inspired Me to Create This Repo
- Ashley G. Williams
- Dan Abramov
- Douglas Crockford
- Eric Elliott
- Kyle Simpson
- Mattias P Johansson
- Aldwin Vlasblom
- GitHub: @Avaq
- Ali Sharif
- André Medeiros (aka André Staltz)
- Brian Cavalier
- Brian Lonsdorf
- Buzz de Cafe
- Christoph Hermann
- David Chambers
- David Chase
- Gleb Bahmutov
- Hardy Jones
- Ian Hofmann-Hicks
- James Forbes
- James Sinclair
- Juan Soto
- GitHub: @sotojuan
- Luke Westby
- Reginald Braithwaite
- Roman Pominov
- Simon Friis Vindum
- Tom Harding
- Tylor Steinberger
- Yassine Elouafi