我正在构建一个相当复杂的网络应用程序,它从一个主菜单开始,用户可以在其中进行初始选择。这是我第一次在 JavaScript 中使用继承尝试真正的 OOP 方法,并且遇到了第一个问题,即“this”关键字没有引用我期望的内容。我猜测这是我的 OOP/继承方法中更广泛问题的结果,因此我希望得到一个答案,它不仅告诉我如何解决这个单独的问题,而且还为我的一般方法提供更深入的反馈和建议。
我只会发布 JS 代码,因为我认为 HTML 不相关,但如果有必要,我当然也可以发布它。
以下代码定义了主类Select
。然后,它创建一个名为 SelectNum
的 Select
子类(查看代码末尾)。在 SelectNum
中,我试图重写 Select
的 mouseover
方法,但不是完全重写 - 我想首先调用 super 的(Select 的) 方法,然后运行一些附加代码。但是当这个子类的 mouseover
方法运行时,我立即收到以下错误:
“未捕获类型错误:无法调用未定义的方法‘stop’”
基本上,this.shine
是未定义的。
首先,我使用 O'Reilly 的 JavaScript:权威指南中的以下代码:
function inherit(p) {
if (Object.create){ // If Object.create() is defined...
return Object.create(p); // then just use it.
}
function f() {}; // Define a dummy constructor function.
f.prototype = p; // Set its prototype property to p.
return new f(); // Use f() to create an "heir" of p.
}
我的代码:
Select = function(el){
return this.init(el);
}
Select.prototype = {
init: function(el){
var that = this;
this.el = el;
this.shine = el.children('.selectShine');
el.hover(function(){
that.mouseover();
},function(){
that.mouseout();
});
return this;
},
mouseover: function(){
this.shine.stop().animate({opacity:.35},200);
},
mouseout: function(){
var that = this;
this.shine.stop().animate({opacity:.25},200);
}
}
//Sub-classes
SelectNum = function(el){
this.init(el);
this.sup = inherit(Select.prototype); //allows access to super's original methods even when overwritten in this subclass
return this;
}
SelectNum.prototype = inherit(Select.prototype);
SelectNum.prototype.mouseover = function(){
this.sup.mouseover(); //call super's method... but this breaks down
//do some other stuff
}
编辑
雷诺斯的回应奏效了。 this.sup.mouseover()
不再抛出错误,并且运行了正确的代码。但是,我实际上需要创建一个名为 SelectLevel
的 SelectNum
子类。与覆盖其父类(super class)的 mouseover()
方法的 SelectNum
不同,SelectLevel
不需要覆盖 SelectNum
的 mouseover()
方法:
SelectLevel = function(el){
this.init(el);
this.sup = inherit(SelectNum.prototype); //allows access to super's original methods even when overwritten in this subclass
for(var k in this.sup){
this.sup[k] = this.sup[k].bind(this);
}
}
SelectLevel.prototype = inherit(SelectNum.prototype);
使用此代码,mouseover()
方法将被连续调用。我相信这是因为 this
现在绑定(bind)到 SelectLevel
对象,因此 this.sup
位于 this.sup.mouseover(
始终引用 SelectNum
中的 )SelectNum
,因此它只是不断调用自身。
如果我删除 SelectLevel
中的 this.sup[k] = this.sup[k].bind(this);
绑定(bind),则会收到错误未捕获类型错误:无法调用未定义的“鼠标悬停”方法
。看起来 this.sup.mouseover()
被连续调用,调用原型(prototype)链中每个对象的 mouseover
方法。当它达到 Object
时,就会抛出此错误,因为 Object
当然没有 sup
属性。
看来我可以通过删除 SelectLevel
中的 this.sup[k] = this.sup[k].bind(this);
绑定(bind)来解决这个问题,然后将 this.sup.mouseover()
包装在 if 语句中,该语句在调用 mouseover()
方法之前首先检查 sup
属性上面:即 if(this.sup !== undefined)
,但这确实感觉不对。
最终,我认为我遗漏了一些关于如何在 JavaScript 中进行子类化的基本知识。虽然这些特定问题的解决方案确实让我们了解了原型(prototype)继承在 JS 中的工作原理,但我确实认为我需要在更广泛的层面上有更好的理解。
最佳答案
this.sup.mouseover();
调用对象 this.sup
上的 .mouseover
方法。你想要的是
this.sup.mouseover.call(this)
您不想在 this.sup
上调用它,而是想在 this
上调用它。
如果这很麻烦,那么你可以在构造函数中执行以下操作
this.sup = inherit(Select.prototype);
for (var k in this.sup) {
if (typeof this.sup[k] === "function") {
this.sup[k] = this.sup[k].bind(this);
}
}
这基本上意味着使用相同的函数覆盖每个方法,但将 this
的值硬绑定(bind)到您期望/想要的值。
关于javascript - "this"关键字的继承和问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7837788/