Skip to content

Instantly share code, notes, and snippets.

@jashkenas
Created November 1, 2011 01:49
Show Gist options
  • Save jashkenas/1329619 to your computer and use it in GitHub Desktop.
Save jashkenas/1329619 to your computer and use it in GitHub Desktop.
// Here is a proposal for minimalist JavaScript classes, humbly offered.
// There are (at least) two different directions in which classes can be steered.
// If we go for a wholly new semantics and implementation, then fancier classical
// inheritance can be supported with parallel prototype chains for true inheritance
// of properties at both the class and instance level.
// If however, we keep current JavaScript prototype semantics, and add a form that
// can desugar to ES3, things must necessarily stay simpler. This is the direction
// I'm assuming here.
// If we want to have static class bodies (no executable code at the top level),
// then we would do well to reuse the known and loved JavaScript idiom for
// fixed lists of properties -- the object literal.
// First, basic usage from a real-world library (Three.js)
class Color {
constructor: function(hex) {
...
},
r: 1, g: 1, b: 1,
copy: function(color) {
...
},
setRGB: function(r, g, b) {
...
},
setHSV: function(h, s, v) {
...
}
}
// To create a class with its prototype chain set correctly:
class Fox extends Animal {
...
}
// Note that "Animal" here is a class object (constructor function) in its
// own right. Fox.prototype is set to an instance of Animal that has been
// constructed without calling its constructor function -- this is the
// usual two-step setting-up-a-prototype shuffle.
// There is no special syntax for setting class-level properties, as they are
// relatively rare. Just add them to the class object itself:
Fox.CONSTANT = value;
// Note that the right-hand side of a class definition is just an expression,
// an object literal is not required. You can be fully dynamic when creating a
// class:
class Student objectContainingStudentProperties
// Or even:
class Protester merge(YoungAdult, WorkEthic, Idealism, {
student: true
})
// The point I'm trying to make being that the own properties of the right hand
// side, however they're derived, become the prototypal properties of the resulting
// class.
// Similarly, class definitions are themselves expressions, and anonymous classes
// are equally possible:
animals.push(class Fox {});
var subclass = function(parent) {
return class extends parent;
};
// Naturally, classes can be built up programmatically in this fashion.
var generateModelClass = function(columns) {
var definition = {};
columns.forEach(function(col) {
definition['get' + col] = function() {
return this[col];
};
definition['set' + col] = function(value) {
return this[col] = value;
};
});
return class definition;
};
// Finally, the Monster class from the current nutshell proposal
// (http://wiki.ecmascript.org/doku.php?id=harmony:classes#the_proposal_in_a_nutshell)
// ... sans unnecessary restrictions:
class Monster {
constructor: function(name, health) {
this.name = name;
this.health = health;
},
attack: function(target) {
log("The monster attacks " + target);
},
isAlive: function() {
return this.health > 0;
},
setHealth: function(value) {
if (value < 0) {
throw new Error("Health must be non-negative.");
}
this.health = value;
},
numAttacks: 0,
attackMessage: "The monster hits you!"
}
// I think that's about the run of it. Note what is left out: public / private /
// static / frozen / const properties and their ilk. Personally, I'm of the view
// that all of these modifiers are deeply undesirable in a language as dynamic
// as JavaScript and won't be much used, if added ... but I also think that
// getters and setters should be deprecated and removed.
// If public / private / static / frozen / const must be a part of class syntax
// in JS.next, then they must be valid prefixes for object literals as well --
// and can easily be used to define classes with those properties under this
// proposal.
// There are no new semantics here, and these classes can easily be transpiled
// into ES3 if needed -- just simpler declaration of constructors with prototypal
// properties and correctly configured prototype chains.
// tl;dr
// Classes are a new expression with the form ([] means optional):
// class [name] [extends parent] [expression]
@dherman
Copy link

dherman commented Nov 1, 2011

@Mpdreamz: as for multiple constructors, isn't it enough just to define different functions? Either as top-level functions or as class properties?

@dherman
Copy link

dherman commented Nov 1, 2011

For contrast, this is the class design that @arv, @samth and I sketched out at the last TC39 meeting:

https://gist.github.com/1330478

Same idea as here, except the body is only a literal, not an arbitrary expression. This is simpler and more friendly to super(), but you can still dynamically compute classes.

@dshaw
Copy link

dshaw commented Nov 1, 2011

As someone who's generally not a fan of adding Classes to JS, I actually like this. Smells like JavaScript. +1

@getify
Copy link

getify commented Nov 1, 2011

+1 i'm not a fan of inheritance-based programming in dynamic languages, in general, but if we're going to add it to the language as a first-class construct, I think this example makes a lot of sense.

@indexzero
Copy link

Very nice work Jeremy. I agree with you that access modifiers seem to not sit well with the dynamic nature of Javascript. I would use this language feature of it existed.

@gordonbrander
Copy link

A thousand times yes! This feels elegant and JavaScript-esque. I also appreciate that it doesn't throw prototypal inheritance under the bus.

@clifton
Copy link

clifton commented Nov 1, 2011

Great implementation of classes in JS. 👍

@pvorb
Copy link

pvorb commented Nov 2, 2011

Why not simply use Dart?

@rwaldron
Copy link

rwaldron commented Nov 2, 2011

Why not simply troll elsewhere?

@csuwildcat
Copy link

The problem with Dart, is that Google presents a false choice. Their premise is that JS is evolving too slowly, while V8 lags far behind Mozilla in implementing the kickass new language features found in more recent versions of ECMAScript. It is disingenuous to say things aren't moving fast enough when your JS engine is two dot revisions behind the implementation of your closest competitor. If Google first implemented proxies, custom iterators, generators, modules, traits, and a whole host of other stuff that is either in, or soon to land in, Mozilla's JS engine then perhaps I would listen to then when they talk about JS not having the features they need.

Google Dart analogy: Google is at a car dealership complaining that the stripped-down dragster it bought has no air conditioner and is threatening to trade it in for a different car to get one....all as the employee points behind him at a whole wall of ready-to-install air conditioners.

@dherman
Copy link

dherman commented Nov 2, 2011

@csuwldcat: With all due respect, I don't really agree with this take. Google is not a monolith — there are plenty of people at Google who believe very much in JS and making it succeed, and we have colleagues and friends at Google, some active on TC39, who are working hard to implement Harmony features. They already have landed proxies and maps and sets in V8 (we haven't finished maps and sets but we're working on it; see https://bugzilla.mozilla.org/show_bug.cgi?id=697479 for progress), I believe they have made progress on block scoping and possibly private names as well.

The future of JS looks freaking awesome, and this is in no small part thanks to the recent progress in V8. To quote Brendan: "People are finally realizing that with V8 prototyping alongside SpiderMonkey, ES6 is happening."

@csuwildcat
Copy link

That's great news Dave, I had no idea Google had proxies live in Chrome yet (easily a favorite new language feature of mine), I hope they continue at the speed you have indicated as it will begin to beg the question "Why Dart again?"

@naholyr
Copy link

naholyr commented Nov 2, 2011

Why not just using popular coffeescript implementation ?

@nzakas
Copy link

nzakas commented Nov 2, 2011

Very interesting stuff. I wonder if there's a way to split the difference. It looks like ES6 has the concept of StructType, which is a constructor that accepts an object literal defining how it should behave. So why not do the same for classes (or as I prefer to call them, types):

var Color = new Type({

  constructor: function(hex) {
    ...
  },

  r: 1, g: 1, b: 1,

  copy: function(color) {
    ...
  },

  setRGB: function(r, g, b) {
    ...
  },

  setHSV: function(h, s, v) {
    ...
  }

});

This fits into the paradigms being introduced in ES6, allows you to define a type easily with an object literal, and doesn't introduce new syntax. It would at least be a baby step towards the end goal of more easily defining custom types.

@tj
Copy link

tj commented Nov 2, 2011

it's kinda sad that ES people can't come up with something minimal like this. It looks much nicer than the horrid proposal, so for that I would +1 it I guess, though I think classes are pretty restrictive, not the inheritance model I would want.

"but I also think that
// getters and setters should be deprecated and removed." - I agree 100%, proxies too

@anentropic
Copy link

Looks nice!!

"Note what is left out: public / private / static / frozen / const properties and their ilk. Personally, I'm of the view that all of these modifiers are deeply undesirable in a language as dynamic as JavaScript and won't be much used, if added"

I'm of the more pessimistic view that they should be left out because they will be used everywhere if added :)

@rwaldron
Copy link

rwaldron commented Nov 2, 2011

@visionmedia I'm curious, why the opposition to Proxy?

@tj
Copy link

tj commented Nov 2, 2011

@rwldrn probably not the right thread for that. new gist? haha :D

@rwaldron
Copy link

rwaldron commented Nov 2, 2011

@visionmedia - Sure, but you brought it up here 0_o

@tj
Copy link

tj commented Nov 2, 2011

@rwldrn https://gist.github.com/1334751
no point spamming this gist

@juandopazo
Copy link

I'm really glad to see the community react so positively to classes as annotated object literals. I hope T39 listens to it :D

@Garciat
Copy link

Garciat commented Nov 3, 2011

I like it. It is very JavaScript-like, and that is what we should be aiming for. The new class syntax should be nothing but shortcuts for what we today do manually. Anything else beyond that is just drifting away from true JS.

@BrendanEich
Copy link

@juandopazo: you read es-discuss, so you should know that @allenwb and others have been pursuing class bodies as object literals. That didn't start here. Thanks to @jashkenas for rekindling it and using a gist (gist + email >> email), but your TC39 vs. the community spin is kinda lousy. Credit where due.

/be

@juandopazo
Copy link

@BrendanEich absolutely! In fact my first comment on this gist has a link to @allenwb 's first proposal. I meant no disrespect at all.

@jiggliemon
Copy link

I like how the ES proposal drops the function statement on class methods.

@tj
Copy link

tj commented Nov 4, 2011

@jiggliemon it's inconsistent, more grammar is not necessarily a better thing, it's easier for people catch on if you utilize what's already there. I dont personally se "function" as a problem, but that's the thing worth tackling in a consistent manner

@chrisdickinson
Copy link

Hey, I've got a hacked-up implementation of this proposal here. It also adds two new operators (strong binding unary and binary :), as well as multiline strings.

I'd love some thoughts!

@geddski
Copy link

geddski commented Mar 23, 2012

I'll always remember this as the sad day when spammers found out about github. Report @StevenGerrard.

@wjcrowcroft
Copy link

wjcrowcroft commented Mar 23, 2012 via email

@csuwildcat
Copy link

csuwildcat commented Mar 23, 2012 via email

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