9.6. Extending Without InheritingThe discussion of creating subclasses earlier in this chapter explains how to create a new class that inherits the methods of another. JavaScript is such a flexible language that subclassing and inheritance is not the only way to extend a class. Since JavaScript functions are data values, you can simply copy (or "borrow") the functions from one class for use in another. Example 9-4 shows a function that borrows all the methods in one class and makes copies in the prototype object of another class. Example 9-4. Borrowing methods from one class for use by another
Many methods are tied strongly to the class that defines them, and it makes no sense to try to use them in other classes. But it is possible to write some methods generically so that they are suitable for use by any class, or by any class that defines certain properties. Example 9-5 includes two classes that do nothing but define useful methods that other classes can borrow. Classes like these that are designed for borrowing are called mixin classes or mixins. Example 9-5. Mixin classes with generic methods for borrowing
Here is a simple Rectangle class that borrows the toString( ) and equals( ) methods defined by the mixin classes: // Here is a simple Rectangle class. function Rectangle(x, y, w, h) { this.x = x; this.y = y; this.width = w; this.height = h; } Rectangle.prototype.area = function( ) { return this.width * this.height; } // Borrow some more methods for it borrowMethods(GenericEquals, Rectangle); borrowMethods(GenericToString, Rectangle); Neither of the mixins shown have a constructor function, but it is possible to borrow constructors as well. In the following code, a new class is created named ColoredRectangle. It inherits rectangle functionality from Rectangle and borrows a constructor and a method from a mixin named Colored: // This mixin has a method that depends on its constructor. Both the // constructor and the method must be borrowed. function Colored(c) { this.color = c; } Colored.prototype.getColor = function( ) { return this.color; } // Define the constructor for a new class. function ColoredRectangle(x, y, w, h, c) { this.superclass(x, y, w, h); // Invoke superclass constructor Colored.call(this, c); // and borrow the Colored constructor } // Set up the prototype object to inherit methods from Rectangle ColoredRectangle.prototype = new Rectangle( ); ColoredRectangle.prototype.constructor = ColoredRectangle; ColoredRectangle.prototype.superclass = Rectangle; // And borrow the methods of Colored for our new class borrowMethods(Colored, ColoredRectangle); The ColoredRectangle class extends (and inherits methods from) Rectangle and borrows methods from Colored. Rectangle itself inherits from Object and borrows from GenericEquals and GenericToString. Although any kind of strict analogy is impossible, you can think of this as a kind of multiple inheritance. Since the ColoredRectangle class borrows the methods of Colored, instances of ColoredRectangle can be considered instances of Colored as well. The instanceof operator will not report this, but in Section 9.7.3., we'll develop a more general method for determining whether an object inherits from or borrows from a specified class. |