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 poss开发者_如何学Cible? 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);
}
精彩评论