Custom types (classes) using object literals in JavaScript
This past week, Jeremy Ashkenas (of CoffeeScript fame) started a flurry of discussion around class syntax for JavaScript. ECMAScript Harmony is scheduled to have classes and the proposal has been up for a while. Of course, JavaScript has never had a true concept of classes (which is why I call them “types” instead), and the current strawman is no exception – it simply creates some syntactic sugar on top of the current constructor/prototype method of defining custom types. An example:
class Color {
constructor(hex) {
...
}
public r = 1;
public g = 1;
public b = 1;
copy(color) {
...
}
setRGB(r, g, b) {
...
}
setHSV(h, s, v) {
...
}
}
This would be instead of defining a separate constructor and prototype. The above desugars to:
function Color(hex){
...
}
Color.prototype.r = 1;
Color.prototype.g = 1;
Color.prototype.b = 1;
Color.prototype.copy = function(color){
...
};
Color.prototype.setRGB = function(r,g,b){
...
};
Color.prototype.setHSV = function(h,s,v){
...
};
Essentially the new class syntax just helps you define the prototype of the new type while the constructor is responsible for creating instance members.
Jeremy didn’t like it, and so came up with an alternate proposal in the form of a gist. At the center of his idea: use the familiar object literal syntax to define new types with just a small amount of syntactic sugar to make things easier.
class Color {
constructor: function(hex) {
...
},
r: 1, g: 1, b: 1,
copy: function(color) {
...
},
setRGB: function(r, g, b) {
...
},
setHSV: function(h, s, v) {
...
}
}
Jeremy’s proposal looks closer to object literal syntax with the class keyword and the type name. A lot of commenters on the gist liked this idea – I’m actually not one of them, I think the proposed Harmony syntax is much more succinct and implements sugaring of known patterns in a straightforward way.
Regardless, there is something to Jeremy’s approach of being able to define new custom types in one step. It’s pretty trivial to do that today using JavaScript. First, you need a simple function:
function type(details){
details.constructor.prototype = details;
return details.constructor;
}
That’s all it takes. Basic usage:
var Color = type({
constructor: function(hex) {
...
},
r: 1, g: 1, b: 1,
copy: function(color) {
...
},
setRGB: function(r, g, b) {
...
},
setHSV: function(h, s, v) {
...
}
});
var mycolor = new Color("ffffff");
The syntax is just a bit different from Jeremy’s as it adheres to ECMAScript 5 syntax, but works pretty much the same way. The key to understanding this approach is understanding the constructor property. You may be used to accessing constructor from an object instance to get the function that created the object. However, constructor is actually a prototype property, shared by all instances. For any given function created from scratch:
function f(){}
console.log(f === f.prototype.constructor); //true
So basically, the type() function takes the passed-in object and looks for the constructor property. At first, details.constructor.prototype has its default value. The function overwrites the prototype with the details object itself (which already has an appropriate reference to constructor). Then, it simply returns the now-fully-formed constructor function. You can start to use the returned constructor with new immediately.
In lieu of Harmony’s new syntax, I’ve very quickly come to like this approach. Using a single object literal is quick and easy, and of course, works right now in all browsers. There are also any number of ways you could modify type() in order to support things like inheritance and mixins, depending on your use cases.
In the end, I’m looking forward to having some syntactic sugar for defining custom types in JavaScript. We’ve battled for too long with overly-verbose composition statements while those using class-based languages looked over our shoulders and laughed. I, for one, welcome our new Harmony overlords.
Update (04-Nov-2011): Fixed Harmony example.
Disclaimer: Any viewpoints and opinions expressed in this article are those of Nicholas C. Zakas and do not, in any way, reflect those of my employer, my colleagues, Wrox Publishing, O'Reilly Publishing, or anyone else. I speak only for myself, not for them.
Both comments and pings are currently closed.




9 Comments
Isn’t there a typo in the Harmony example? Properties are assigned as an expression, not as an object literal property, aren’t they?
I’m not a fan of the syntax for declaring methods in the Harmony proposal… they look too much like a function invocation, and the last thing we need in new syntax is ambiguity.
Great thinking around the use of type()! I really like that syntax… very clean and easy to understand!
Steve Carlson on November 4th, 2011 at 1:27 pm
Sorry, the Harmony example is actually from Brendan’s gist that was created in response to Jeremy’s. You’re right, the current Harmony proposal is a bit different. I’ll update that description.
Nicholas C. Zakas on November 4th, 2011 at 2:15 pm
The biggest benefit of getting “classes” into Harmony is going to be the unification of the many, slightly different, sometimes incompatible patterns being used all over the web. I’m definitely looking forward to that!
Jay on November 4th, 2011 at 3:52 pm
Wait, why would you promote the use or even use the .constructor property? It’s an idle property and has nothing to do with “classes” in current js… It will not fix your prototypal inheritance chain, that’s for damn sure. So am I missing something?
It seems to me like your type function should’ve been something like this:
function type(details){
var ctr = details.constructor;
ctrl.__proto__ = details;
return ctrl;
}
Of course this pattern is currently impossible in exisiting js/es semantics (it’s the Array subclassing problem).
I wrote my own class ideas up too: http://qfox.nl/weblog/243
Peter van der Zee on November 6th, 2011 at 3:12 am
@Peter – I think you’re missing something. I’m not entirely sure what your objection is to using
constructor. The function that you created is completely different than mine because you’re changing the prototype of the constructor function (essentially, replacing the reference toFunction.prototypethat would already be in__proto__) whereas mine is changing the prototype of the constructor (changing the value of__proto__fromObject.prototypetodetails). These are two very different things – I’m not solving the array subclassing problem (and not trying to), I’m just trying to create a one-step way of defining custom types.I’d suggest trying to use my function a bit to better understand what it’s doing as it relates to the more classic pattern I described earlier.
Nicholas C. Zakas on November 6th, 2011 at 12:06 pm
Oh, wow. I was way off there. Sorry about that. I completely miss-read that function AND proposed a bad alternative :/ You were already doing what I wanted to demonstrate :p *cries in a corner now*
Peter van der Zee on November 6th, 2011 at 3:50 pm
Looks like Harmony’s syntax included visibility in properties.
I dont really see the point in adding new ways to write the same stuff, as Jay says it would be difficult to unite all the different approaches out there. Though defining properties visibility would be an advance.
Federico Bana on November 7th, 2011 at 4:13 am
I like this approach, you write the current constructor data structure, but prototype-first, turned inside out.
My favorite for ECMAScript.next would be object exemplars:
http://www.2ality.com/2011/11/javascript-classes.html
[My post also mentions ES.next proposals that compete with Ashkenas’ one.]
Axel Rauschmayer on November 7th, 2011 at 7:49 am
[...] Finally, Nicholas Zakas offered a summary of Jeremy’s proposal and offered his own backwards-compatible version. [...]
JavaScript Magazine Blog for JSMag » Blog Archive » News roundup: 11-11-11! insertAdjacentHTML, classes in JavaScript?, twilight of Flash and Silverlight, Yahoo! Cocktails on November 11th, 2011 at 11:31 am
Comments are automatically closed after 14 days.