Skip to content

Instantly share code, notes, and snippets.

@rauschma
Created May 13, 2012 04:23
Show Gist options
  • Save rauschma/2680473 to your computer and use it in GitHub Desktop.
Save rauschma/2680473 to your computer and use it in GitHub Desktop.
Class declarations with object exemplar semantics
//----- Example code:
// Class declarations:
// - No data properties allowed
// - Future: support mixins
// - Optional: call the initialization method `new` instead of `constructor`
// Superclass
class Person {
constructor(name) {
this.name = name;
}
describe() {
return "Person called "+this.name;
}
}
// Subclass
class Employee extends Person {
constructor(name, title) {
super.constructor(name);
this.title = title;
}
describe() {
return super.describe()+" ("+this.title+")";
}
});
var jane = new Employee("Jane", "CTO");
console.log(jane instanceof Person); // true
//----- Desugars to:
// Advantages:
// - You can always write Person.* instead of Person.prototype.*
// - Subtyping becomes very easy
// More information: http://www.2ality.com/2011/06/prototypes-as-classes.html
var Person = {
constructor: function (name) {
this.name = name;
},
describe: function() {
return "Person called "+this.name;
}
};
var Employee = Object.create(Person);
Employee.constructor = function (name, title) {
Employee.super.constructor.call(this, name);
this.title = title;
};
Employee.describe = function () {
return Employee.super.describe.call(this)+" ("+this.title+")";
};
var jane = Object.create(Employee);
jane.constructor("Jane", "CTO");
console.log(Person.isPrototypeOf(jane));
//----- Same functionality, via the library Proto.js, https://github.com/rauschma/proto-js
var Person = Proto.extend({
constructor: function (name) {
this.name = name;
},
describe: function() {
return "Person called "+this.name;
}
});
var Employee = Person.extend({
constructor: function (name, title) {
Employee.super.constructor.call(this, name);
this.title = title;
},
describe: function () {
return Employee.super.describe.call(this)+" ("+this.title+")";
}
});
var jane = Employee.new("Jane", "CTO");
console.log(Person.isPrototypeOf(jane));
//----- Compatibility with (legacy) constructor functions
// - To extend a constructor function Foo, you write: `extends Foo.prototype`
// Could be handled automatically, by checking whether the operand of `extends` is a function.
// Proto.js comes with support for extending constructor functions.
@k33g
Copy link

k33g commented May 13, 2012

i <3 that :)
perhaps you should named constructors : constructor: function Person (name) / Employee.constructor = function Employee (name, title)

then jane is no longer an object but a person. I would appreciate your opinion on this.

what would be the easiest way to manage static members with your example or with proto-js ?

Have a nice day
Philippe

@rauschma
Copy link
Author

You are using named function expressions. Note that their names are only visible to themselves, not anywhere else.
What you can do is define a constructor function in a manner that looks almost like the code above:

function Class(proto) {
    proto.constructor.prototype = proto;
    return proto.constructor;
}

var Person = Class({
    constructor: function (name) {
        this.name = name;
    },
    describe: function() {
        return "Person called "+this.name;
    }
});

In this case, Person is an old-school constructor function, with all associated complications (e.g. subtyping being a bit tricky). That is roughly how the proposed maximally minimal class declarations [1] for ECMAScript.next work.

[1] http://wiki.ecmascript.org/doku.php?id=strawman:maximally_minimal_classes

@rauschma
Copy link
Author

As for constructor properties (static properties): Those are used in Java to simulate first-class functions and in JavaScript to simulate namespaces. Hence, with ECMAScript.next having modules, there will be much less use for them. For object exemplars, there is no difference between prototype properties and static properties.

@k33g
Copy link

k33g commented May 13, 2012

:) thank you for your answer(s).

"their names are only visible to themselves, not anywhere else."
But i can test like this :

jane.constructor.name
//or :
jane.__proto__
// and (i know, not very nice)
Object.prototype.getTypeName = function () { return this.constructor.name; }

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