问题
In another SO question about whether to call a super-constructor or use the prototype chain the answer provided by one of the users seemed sensible but didn't work for me when I implemented it on my solution which has multiple layers of inheritance.
Here's the answer I'm referring to: https://stackoverflow.com/a/4389429/392591
So I've created a jsFiddle using this custom extend method to illustrate the problem: https://jsfiddle.net/68q7yghv/
I've added the jsFiddle code at the bottom.
In my test I've created a 4 tier class inheritance structure from baseClass through to subSubSubClass each of which (except the baseClass) use the 'extend' method to inherit from the previous sub-class. When you hit the test button I'm printing out class.baseClassMethod to see if it finds it, but it only finds it for the base class.
You should see the following results:
function () { this.output += "baseClassMethod"; }
undefined
undefined
undefined
Is it possible that the cause is that the call to the super constructor is messing with the 'this' context?
function extend(baseClass, subClass) {
var originalPrototype = subClass.prototype;
subClass.prototype = Object.create(baseClass.prototype);
for (var key in originalPrototype) {
subClass.prototype[key] = originalPrototype[key];
}
subClass.prototype.constructor = subClass;
Object.defineProperty(subClass.prototype, 'constructor', {
enumerable: false,
value: subClass
});
};
var baseClass = function() {
this.output = "Base: ";
this.toggleWizardHandlers = [];
this.baseClassMethod = function() {
this.output += "baseClassMethod";
};
};
baseClass.prototype.on = function(eventName, handler) {
switch (eventName.toLowerCase()) {
case "togglewizards":
return this.toggleWizardHandlers.push(handler);
break;
}
};
baseClass.prototype.toggleWizards = function(newWizard, newStepIndex) {
var handler, i, len, ref;
ref = this.toggleWizardHandlers;
for (var i = 0; i < ref.length; i++) {
handler = ref[i];
setTimeout(handler, 0, newWizard, newStepIndex);
}
};
var subClass = function() {
baseClass(this);
};
extend(baseClass, subClass);
var subSubClass = function() {
subClass(this);
};
extend(subClass, subSubClass);
var subSubSubClass = function() {
subSubClass(this);
};
extend(subSubClass, subSubSubClass);
var manager = function(settings) {
this.log = function(message) {
$("#log").html($("#log").html() + "<br />" + message);
};
this.clearLog = function() {
$("#log").html("");
};
this.testBaseClass = new baseClass();
this.testSubClass = new subClass();
this.testSubSubClass = new subSubClass();
this.testSubSubSubClass = new subSubSubClass();
//test.on("toggleWizards", function(param) { that.log(param); });
};
$(function() {
var manage = new manager("");
$("#btn").click(function() {
manage.log("start test");
manage.clearLog();
try {
manage.log(manage.testBaseClass.baseClassMethod);
} catch (e) {
manage.log(e);
}
try {
manage.log(manage.testSubClass.baseClassMethod);
} catch (e) {
manage.log(e);
}
try {
manage.log(manage.testSubSubClass.baseClassMethod);
} catch (e) {
manage.log(e);
}
try {
manage.log(manage.testSubSubSubClass.baseClassMethod);
} catch (e) {
manage.log(e);
}
});
});
回答1:
Your prototype inheritance is working, you can try to access on
or toggleWizards
on all your instances.
Your super calls in the constructors lack a crucial part though: .call. Without it, you are passing this
for the first parameter, not as the this
argument. Your base class is not able to initialise any properties on the subclass instance without this:
function subClass() {
baseClass.call(this);
// ^^^^
}
回答2:
When you call the super constructor, you need to use apply
, not call it as a simple function.
var subClass = function() {
baseClass.apply(this);
};
Otherwise your sub-classes new this
object is passed as the first argument to the super constructor and this
will refer to the global object (or null in strict mode).
A small thing, it common to Capitalise constructor functions so that its clear that they should be called with new
and not as regular functions.
来源:https://stackoverflow.com/questions/35696180/javascript-sub-classing-super-constructors-and-using-custom-extend-loses-base-c