Skip to content

Instantly share code, notes, and snippets.

@vasanthk
Forked from ericelliott/es7-class.md
Created November 18, 2015 08:11
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vasanthk/de1d7385cf51eadb2916 to your computer and use it in GitHub Desktop.
Save vasanthk/de1d7385cf51eadb2916 to your computer and use it in GitHub Desktop.
Let's fix `class` in ES7

Two Simple Changes to Simplify class

I'm not suggesting drastic action. I don't want to break backwards compatibility. I simply want to make the class feature more usable to a broader cross section of the community. I believe there is some low-hanging fruit that can be harvested to that end.

Imagine AutoMaker contained class Car, but the author wants to take advantage of prototypes to enable factory polymorphism in order to dynamically swap out implementation.

Stampit does something similar to this in order to supply information needed to inherit from composable factory functions, known as stamps.

This isn't the only way to achieve this, but it is a convenient way which is compatible with .call(), .apply(), and .bind().

There are also other compelling reasons to refactor from a class to a factory, including the desire to utilize object pools instead of fresh instances, etc...

'use strict';

let AutoMaker = {
  Car (bundle) {
    return Object.create(this.bundle[bundle]);
  },

  bundle: {
    premium: {
      getOptions: function () {
        return ['leather', 'wood', 'pearl'];
      }
    }
  }
};

// The refactored factory expects:
let bar = AutoMaker.Car('premium');

// But since it's a library, lots of callers
// in the wild are doing this:
let oldCar = new AutoMaker.Car('premium');

// Which of course throws:
// TypeError: Cannot read property 'premium' of
// undefined at new AutoMaker.Car

The problem is that the new keyword hijacks this.

This is a really important problem to solve, because refactoring wrong class hierarchies into more composable pieces is a very common activity. I believe this problem is big enough that it's worth solving in the language spec.

For instance, we could deprecate new and drop the new requirement for ES7 class. Old classes would still be hard to refactor, but new ones would be significantly improved.

Since it wouldn't require a breaking change, I consider this to be low hanging fruit, ripe for the picking.

But we could go further:

Some people will be expecting things like instanceof to "work" with classes. The problem is that instanceof works well enough, until it doesn't. We train programmers to rely on it and then when they try to use it across execution contexts, iFrames, etc..., they get frustrated and stuck.

I recently ran across an otherwise awesome looking open source library that relied on instanceof and broke across iFrame boundaries in a pretty horrible way. Luckily, there were alternatives on npm that were not broken. Now I'm wishing I made a note of the library name and GitHub issue...

IFrames are not the only place it breaks. We expect something called instanceof to make some guarantees that might be pretty easy to statically analyze, but it relies on a prototype property that is dynamic. Oops.

Hence my suggestion that we also deprecate instanceof.

If we deprecate new and instanceof, it would go a long way to make constructors more usable (and by extension, classes).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment