JavaScript: The Definitive Guide, Sixth Editio javaScript权威指南(第6版) pdf 文字版-文字版, javascript电子书, 和javascript 有关的电子书:

9.7.2 Constructor and Method Chaining

9.7.2 Constructor and Method Chaining

The SingletonSet class in the last section defined a completely new set implementation, and completely replaced the core methods it inherited from its superclass. Often, however, when we define a subclass, we only want to augment or modify the behavior of our superclass methods, not replace them completely. To do this, the constructor and methods of the subclass call or chain to the superclass constructor and the superclass methods.

Example 9-13 demonstrates this. It defines a subclass of Set named NonNullSet: a set that does not allow nulland undefinedas members. In order to restrict the membership in this way, NonNullSet needs to test for null and undefined values in its add()method. But it doesn’t want to reimplement the add() method completely, so it chains to the superclass version of the method. Notice also that the NonNullSet()constructor doesn’t take any action of its own: it simply passes its arguments to the superclass constructor (invoking it as a function, not as a constructor) so that the superclass constructor can initialize the newly created object.

Example 9-13. Constructor and method chaining from subclass to superclass


*NonNullSet is a subclass of Set that does not allow null and undefined*as members of the set. */

function NonNullSet() {

// Just chain to our superclass.

// Invoke the superclass constructor as an ordinary function to initialize

// the object that has been created by this constructor invocation.

Set.apply(this, arguments);


// Make NonNullSet a subclass of Set: NonNullSet.prototype = inherit(Set.prototype); NonNullSet.prototype.constructor = NonNullSet;

// To exclude null and undefined, we only have to override the add() method

NonNullSet.prototype.add = function() {

// Check for null or undefined arguments

for(var i = 0; i < arguments.length; i++)

if (arguments[i] == null)

throw new Error("Can't add null or undefined to a NonNullSet");

// Chain to the superclass to perform the actual insertion

return Set.prototype.add.apply(this, arguments); };

Let’s generalize this notion of a non-null set to a “filtered set”: a set whose members must pass through a filter function before being added. We’ll define a class factory function (like the enumeration() function from Example 9-7 ) that is passed a filter function and returns a new Set subclass. In fact, we can generalize even further and define our class factory to take two arguments: the class to subclass and the filter to apply to its add() method. We’ll call this factory method filteredSetSubclass(), and we might use it like this:

// Define a set class that holds strings only var StringSet = filteredSetSubclass(Set, function(x) {return typeof x==="string";});

// Define a set class that does not allow null, undefined or functions

9.7 Subclasses | 231

var MySet = filteredSetSubclass(NonNullSet, function(x) {return typeof x !== "function";});

The code for this class factory function is in Example 9-14 . Notice how this function performs the same method and constructor chaining as NonNullSet did.

Example 9-14. A class factory and method chaining


*This function returns a subclass of specified Set class and overrides*the add() method of that class to apply the specified filter. */ function filteredSetSubclass(superclass, filter) { var constructor = function() { // The subclass constructor

superclass.apply(this, arguments); // Chains to the superclass }; var proto = constructor.prototype = inherit(superclass.prototype); proto.constructor = constructor; proto.add = function() {

// Apply the filter to all arguments before adding any

for(var i = 0; i < arguments.length; i++) { var v = arguments[i]; if (!filter(v)) throw("value " + v + " rejected by filter");

} // Chain to our superclass add implementation superclass.prototype.add.apply(this, arguments);

}; return constructor; }

One interesting point to note about Example 9-14 is that by wrapping a function around our subclass creation code, we are able to use the superclass argument in our constructor and method chaining code rather than hard-coding the name of the actual superclass. This means that if we wanted to change the superclass, we would only have to change it in one spot, rather than searching our code for every mention of it. This is arguably a technique that is worth using, even if we’re not defining a class factory. For example, we could rewrite our NonNullSet using a wrapper function and the Function.prototype.extend() method (of Example 9-11 ) like this:

var NonNullSet = (function() { // Define and invoke function var superclass = Set; // Only specify the superclass once. return superclass.extend(

function() { superclass.apply(this, arguments); }, // the constructor { // the methods

add: function() { // Check for null or undefined arguments for(var i = 0; i < arguments.length; i++)

if (arguments[i] == null) throw new Error("Can't add null or undefined");

// Chain to the superclass to perform the actual insertion return superclass.prototype.add.apply(this, arguments);


}); }());

Finally, it is worth emphasizing that the ability to create class factories like this one arises from the dynamic nature of JavaScript. Class factories are a powerful and useful feature that has no analog in languages like Java and C++.

友情链接It题库(| 版权归yishouce.com所有| 友链等可联系|粤ICP备16001685号-1