我正在构建一个相当复杂的 Web 应用程序,它从用户进行初始选择的主菜单开始。这是我第一次尝试在 JavaScript 中使用继承的真正 OOP 方法,我遇到了第一个问题,即“this”关键字不是我期望的。我猜这是我的 OOP/继承方法存在更广泛问题的结果,所以我希望得到一个答案,它不仅可以告诉我如何解决这个单独的问题,还可以为我的一般方法提供更深入的反馈和建议。
我只会发布 JS 代码,因为我认为 HTML 不相关,但如果有必要,我当然也可以发布。
下面的代码定义了主类Select
。然后它创建一个Select
被调用的子类SelectNum
(看代码的末尾)。在SelectNum
中,我试图覆盖 的mouseover
方法Select
,但不是完全覆盖——我想先调用 super 的(Select's)方法,然后运行一些额外的代码。但是当这个子类的mouseover
方法运行时,我立即得到以下错误:
“未捕获的类型错误:无法调用未定义的方法‘停止’”
基本上,this.shine
是未定义的。
首先,我使用 O'Reilly 的 JavaScript: The Definitive Guide 中的以下代码:
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
}
编辑
Raynos 的回应奏效了。this.sup.mouseover()
不再抛出错误,并且运行了正确的代码。但是,我实际上需要创建一个SelectNum
名为SelectLevel
. 与SelectNum
覆盖其超类的mouseover()
方法不同,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
现在绑定到SelectLevel
对象,所以this.sup
在行this.sup.mouseover()
中SelectNum
总是指代SelectNum
,所以它只是不断地调用自己。
如果我删除 中的this.sup[k] = this.sup[k].bind(this);
绑定SelectLevel
,则会收到错误消息Uncaught TypeError: Cannot call method 'mouseover' of undefined
。它似乎this.sup.mouseover()
被连续调用,调用mouseover
原型链中每个对象的方法。当它达到 时Object
,就会引发此错误,因为当然,Object
它没有sup
属性。
似乎我可以通过删除 in 的this.sup[k] = this.sup[k].bind(this);
绑定来解决这个问题SelectLevel
,然后将 in 包装this.sup.mouseover()
在一个 if 语句中,该语句首先检查sup
属性,然后再调用mouseover()
它的方法: ie if(this.sup !== undefined)
,但这真的感觉不对。
最终,我认为我遗漏了一些关于如何在 JavaScript 中进行子类化的基本知识。虽然这些特定问题的解决方案确实揭示了原型继承在 JS 中的工作原理,但我真的认为我需要在更广泛的层面上更好地理解。