Javascript sub classing、超级构造函数和使用自定义扩展丢失基础 class 方法
Javascript sub classing, super constructors and using custom extend loses base class methods
在另一个关于是调用超级构造函数还是使用原型链的 SO 问题中,一位用户提供的答案似乎是明智的,但当我在我的多层解决方案中实现它时对我不起作用的继承。
这是我指的答案:
所以我使用这个自定义扩展方法创建了一个 jsFiddle 来说明问题:https://jsfiddle.net/68q7yghv/
我在底部添加了 jsFiddle 代码。
在我的测试中,我创建了一个从 baseClass 到 subSubSubClass 的 4 层 class 继承结构,每个继承结构(baseClass 除外)都使用 'extend' 方法从前一个子类继承class。当你按下测试按钮时,我正在打印 class.baseClassMethod 以查看它是否找到它,但它只为基础 class 找到它。
您应该会看到以下结果:
函数 () { this.output += "baseClassMethod"; }
未定义
未定义
未定义
是否有可能是对超级构造函数的调用扰乱了 'this' 上下文?
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);
}
});
});
调用超级构造函数时,需要使用apply
,不能作为简单的函数调用
var subClass = function() {
baseClass.apply(this);
};
否则你的 sub-类 new this
对象将作为第一个参数传递给超级构造函数并且 this
将引用全局对象(或在严格模式下为 null) .
一件小事,大写构造函数很常见,因此很明显它们应该用 new
调用,而不是作为常规函数调用。
您的原型继承有效,您可以尝试在所有实例上访问 on
或 toggleWizards
。
你在构造函数中的超级调用缺少一个关键部分:.call
。没有它,您将传递 this
作为第一个参数,而不是 this
参数。没有这个,你的基础 class 就无法初始化 subclass 实例的任何属性:
function subClass() {
baseClass.call(this);
// ^^^^
}
在另一个关于是调用超级构造函数还是使用原型链的 SO 问题中,一位用户提供的答案似乎是明智的,但当我在我的多层解决方案中实现它时对我不起作用的继承。
这是我指的答案:
所以我使用这个自定义扩展方法创建了一个 jsFiddle 来说明问题:https://jsfiddle.net/68q7yghv/
我在底部添加了 jsFiddle 代码。
在我的测试中,我创建了一个从 baseClass 到 subSubSubClass 的 4 层 class 继承结构,每个继承结构(baseClass 除外)都使用 'extend' 方法从前一个子类继承class。当你按下测试按钮时,我正在打印 class.baseClassMethod 以查看它是否找到它,但它只为基础 class 找到它。
您应该会看到以下结果:
函数 () { this.output += "baseClassMethod"; }
未定义
未定义
未定义
是否有可能是对超级构造函数的调用扰乱了 'this' 上下文?
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);
}
});
});
调用超级构造函数时,需要使用apply
,不能作为简单的函数调用
var subClass = function() {
baseClass.apply(this);
};
否则你的 sub-类 new this
对象将作为第一个参数传递给超级构造函数并且 this
将引用全局对象(或在严格模式下为 null) .
一件小事,大写构造函数很常见,因此很明显它们应该用 new
调用,而不是作为常规函数调用。
您的原型继承有效,您可以尝试在所有实例上访问 on
或 toggleWizards
。
你在构造函数中的超级调用缺少一个关键部分:.call
。没有它,您将传递 this
作为第一个参数,而不是 this
参数。没有这个,你的基础 class 就无法初始化 subclass 实例的任何属性:
function subClass() {
baseClass.call(this);
// ^^^^
}