【发布时间】:2011-12-11 20:58:47
【问题描述】:
我正在构建一个相当复杂的网络应用程序,该应用程序从用户进行初始选择的主菜单开始。这是我第一次尝试在 JavaScript 中使用继承的真正 OOP 方法,我遇到了第一个问题,即“this”关键字不是我期望的。我猜这是我的 OOP/继承方法存在更广泛问题的结果,所以我希望得到一个答案,它不仅可以告诉我如何解决这个单独的问题,还可以为我的一般方法提供更深入的反馈和建议。
我只发布 JS 代码,因为我认为 HTML 不相关,但如果有必要,我当然也可以发布。
以下代码定义了主类Select。然后它创建一个名为SelectNum 的Select 的子类(查看代码末尾)。在SelectNum 中,我试图覆盖Select 的mouseover 方法,但并不完全——我想先调用super 的(Select's)方法,然后运行一些额外的代码。但是当这个子类的mouseover方法运行时,我立即得到如下错误:
"Uncaught TypeError: Cannot call method 'stop' of undefined"
基本上,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 子类。与覆盖其超类的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 现在绑定到SelectLevel 对象,所以SelectNum 中的this.sup.mouseover() 行中的this.sup 总是引用SelectNum,所以它只是不断地调用自己。
如果我删除SelectLevel 中的this.sup[k] = this.sup[k].bind(this); 绑定,则会收到错误Uncaught TypeError: Cannot call method 'mouseover' of undefined。似乎this.sup.mouseover() 被连续调用,在原型链中的每个对象上调用mouseover 方法。当它达到Object 时,就会引发此错误,因为当然Object 没有sup 属性。
看来我可以通过删除SelectLevel 中的this.sup[k] = this.sup[k].bind(this); 绑定来解决这个问题,然后将this.sup.mouseover() 包装在一个if 语句中,该语句首先检查sup 属性,然后再调用mouseover() 方法它:即if(this.sup !== undefined),但这确实感觉不对。
最终,我认为我遗漏了一些关于如何在 JavaScript 中进行子类化的基本知识。虽然这些特定问题的解决方案确实为原型继承在 JS 中的工作原理提供了一些启示,但我真的认为我需要在更广泛的层面上更好地理解。
【问题讨论】:
-
你确定你的继承函数有效吗?
-
是的,Raynos 下面的回答确实解决了这个特定的
this问题。 -
您的
this.sup令人困惑。 I would recommend an alternative。它使用pd
标签: javascript oop inheritance this prototypal-inheritance