简体   繁体   中英

Javascript: Allowing “virtual” function in base class to create instance of subclass

I have the following object model I want to get working - have been banging my head against the clone bit! Is this possible? I can't seem to get access to the SubClass constructor from within the baseclass without hard coding it.

The code is for a queue of arbitrary operations that all share a lot of common functionality; new operations are created as subclasses that merely override the action() method for operation specific functionality.

Is this possible without overriding the clone() method in each subclass?

/*
Application specific subclass:
*/
function SubClass_Operation1()
{
  BaseOperationClass.apply(this, arguments); // Call inherited constructor

  this.action = function()
  {
    this.manager.addToQueue(this.clone({changeValue:1}));
    this.manager.addToQueue(this.clone({changeValue:2}));
    this.manager.addToQueue(this.clone({changeValue:3}));
  }
}
SubClass.prototype = new BaseOperationClass;

// More of these defined for each operation
...

/*
Base class containing all common functionality
*/
function BaseOperationClass(manager)
{
  this.manager = manager;

  // Placeholder for virtual action() function
  this.action = function()
  {
  }

  this.clone = function(mods)
  {
    var res = ?????? // Should create exact copy of current SubClass

    res.applyModifications(mods);
  }

  this.applyModifications(mods)
  {
    ...
  }

  // Lots of common functionality 
  ...
}

To get access in your .clone() method to the constructor without having to hard-code it, a usual solution is to use the .constructor property which each object can set on its own prototype. The leaf object definition, will then have the override on the constructor property and will be the desired constructor to call. As you already seem to know, cloning an object with this method requires some knowledge about arguments that must be sent to the constructor.

This example here uses no arguments for the constructor. It then asks each object to support a .init method that accepts the object it was being cloned from so each class is then responsible for initializing the new clone from the original.

Here's an example in a running snippet:

 function Base() { this.type = "base"; } Base.prototype = { clone: function () { var c = new this.constructor(); // let clone initialize itself from the original c.init(this); return c; }, setName: function(name) { this.name = name; }, init: function(obj) { // copy over name instance data this.name = obj.name; } } // set .constructor property for use with .clone() Base.prototype.constructor = Base; function Derived() { Base.call(this); this.type = "derived"; } // inherit from Base Derived.prototype = Object.create(Base.prototype); Derived.prototype.setOccupation = function(occupation) { this.occupation = occupation; } Derived.prototype.init = function(obj) { // let base object init itself Base.prototype.init.call(this, obj); // copy over our own instance data this.occupation = obj.occupation; } // set .constructor property for use with .clone() Derived.prototype.constructor = Derived; var x = new Derived(); x.setName("Bob"); x.setOccupation("Engineer"); var xx = x.clone(); var y = new Base(); y.setName("Alice"); var yy = y.clone(); log(x !== xx) log(x); log(xx); log(y); log(yy) // function just for output in snippet function log(a) { var div = document.createElement("div"); if (typeof a === "object") { a = JSON.stringify(a); } div.innerHTML = a; document.body.appendChild(div); } 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM