public
Last active — forked from jashkenas/minimalist-classes.js

ECMAScript 6 alternative classes proposal

  • Download Gist
not-so-minimalist-classes.js
JavaScript
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
// tl;dr
// Classes uses same syntax as functions with the form ([] means optional):
// [parent] class [name] (args) {...}
// but class keyword returns the prototype, not the constructor so you can
// extend it right away with (literal) object extension.
// end of tl;dr
 
// The proposal:
 
// Here is a proposal for (less than Jeremy's, but still)
// minimal 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.
 
// Though the "function is class and constructor" principle seem awkward,
// it is part of the language so I would propose reusing it.
 
// The class proposal uses the object literal extension proposed by Allen (I think)
// heavily, but I made some changes to it. Main change is that extension can be made
// by any object not only by literal (literal case can be optimized), using syntax
 
object with extensionObject
 
// (I am abusing with keyword here, giving it more useful meaning).
// (if it would break, some other operator would be handy, like # or ## or **)
 
// First, basic usage from a real-world library (Three.js)
 
class Color (hex) {
...
} with {
 
r: 1, g: 1, b: 1,
 
copy (color) {
...
}
 
setRGB (r, g, b) {
...
}
 
setHSV (h, s, v) {
...
}
 
}
 
// The basic idea is, class keyword would have identical meaning with function
// keyword with one exception: it will return the prototype, not the function.
 
 
// To create a class with its prototype chain set correctly:
 
Animal class Fox (...) {
...
} with {
...
}
 
// Note that "Animal" here is a class object (constructor function) in its
// own right. Fox.prototype is set to the same object as for any proper function,
// with the exception of prototype pre-set to Animal.prototype.
 
// I'd like to see direct use of prototype object, too, but cannot come up
// with nice enough syntax for the moment. If there will be <| operator, I can
 
animalProto <| class Fox (...) {
...
} with {
...
}
 
// It works out of the box.
 
 
 
// 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;
 
// or to make it constant right away,
 
Fox with { CONSTANT:= value };
 
 
// You can then extend the class using object extension right away.
// You can be fully dynamic when creating a class:
 
class Student (...) { ... } with objectContainingStudentProperties
 
// Or even:
 
class Protester (...) { ... } with YoungAdult with WorkEthic with Idealism with {
student: true
}
 
// The point I'm trying to make being that the own properties of the right hand
// side of with, however they're derived, become the prototypal properties of the
// resulting class.
 
 
// Similarly, class definitions are themselves expressions, and anonymous classes
// are equally possible:
 
var subclass = function(parent) {
return parent function () {}; // if you want to return constructor, not prototype
};
 
 
// Naturally, classes can be built up programmatically in this fashion.
 
var generateModelClass = function(columns) {
 
var klass = class () {};
 
columns.forEach(function(col) {
klass with {
get [col] () {
return this[col];
},
set [col] (value) {
return this[col] = value;
}
};
});
 
return class.constructor;
 
};
 
 
// 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 (name, health) {
this.name = name;
this.health = health;
} with {
 
attack (target) {
log("The monster attacks " + target);
}
 
isAlive () {
return this.health > 0;
}
 
setHealth (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 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
 
// (contrary to Jeremy I fear they would be much used, if added, by everyone
// coming from "safe" static-typing final world)
 
// 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.
 
// Also, in line with previous fears of making JS world overly rigid, I'd
// _very_ much proposed the change to inline literal functions so that
// if not explicitly declared
 
{ const method (...) { ... } }
 
// or, in par with :=
 
{ method (...) = { ... } }
 
// they are non-enumerable but writable and configurable. This is a must for
// Javascript world where dynamic changes of running code is part of a dynamic
// culture. Methods proposal is easiest way to write methods (no function keyword),
// so it will be pervasively used and non-writable, non-configurable function
// will appear everywhere. Too rigid.
 
// There are little new semantics here (const and/or non-enum in extended literals,
// and it not part of _class_ proposal per se), so these classes can easily be
// transpiled into ES3 if needed -- just simpler declaration of constructors
// with prototypal properties and correctly configured prototype chains.

@jashkenas, @BrendanEich, @dherman, @Gozala and others: I'd like to hear from you, what do you think about this?

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.