Next: Interoperable Polymorphism, Previous: Using GNU ease.js Classes Outside of ease.js, Up: Interoperability [Contents]
4.2 Prototypally Extending Classes
Since classes are also constructors with prototypes, they may be used as part of a prototype chain. There are, however, some important considerations when using any sort of constructor as part of a prototype chain.
Conventionally, prototypes are subtyped by using a new instance as the prototype of the subtype’s constructor, as so:
var Foo = Class( { /*...*/ } ); // extending class as a prototype function SubFoo() {}; SubFoo.prototype = Foo(); // INCORRECT SubFoo.prototype.constructor = SubFoo;
The problem with this approach is that constructors may perform validations
on their arguments to ensure that the instance is in a consistent state. GNU
ease.js solves this problem by introducing an asPrototype
method on
all classes:
var Foo = Class( { /*...*/ } ); // extending class as a prototype function SubFoo() { // it is important to call the constructor ourselves; this is a // generic method that should work for all subtypes, even if SubFoo // implements its own __construct method this.constructor.prototype.__construct.apply( this, arguments ); // OR, if SubFoo does not define its own __construct method, you can // alternatively do this: this.__construct(); }; SubFoo.prototype = Foo.asPrototype(); // Correct SubFoo.prototype.constructor = SubFoo;
The asPrototype
method instantiates the class, but does not execute
the constructor. This allows it to be used as the prototype without any
issues, but it is important that the constructor of the subtype invokes the
constructor of the class, as in Figure 4.3. Otherwise, the
state of the subtype is undefined.
Keep in mind the following when using classes as part of the prototype chain:
- GNU ease.js member validations are not enforced; you will not be warned if an abstract method remains unimplemented or if you override a non-virtual method, for example. Please exercise diligence.
- It is not wise to override non-virtual methods, because the class designer may not have exposed a proper API for accessing and manipulating internal state, and may not provide proper protections to ensure consistent state after the method call.
- Note the Private Member Dilemma to ensure that your prototype works properly in pre-ES5 environments and with potential future ease.js optimizations for production environments: you should not define or manipulate properties on the prototype that would conflict with private members of the subtype. This is an awkward situation, since private members are unlikely to be included in API documentation for a class; ease.js normally prevents this from happening automatically.
Next: Interoperable Polymorphism, Previous: Using GNU ease.js Classes Outside of ease.js, Up: Interoperability [Contents]