0

我正在构建一个相当复杂的 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不需要覆盖SelectNummouseover()方法:

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 中的工作原理,但我真的认为我需要在更广泛的层面上更好地理解。

4

1 回答 1

2

this.sup.mouseover();

调用.mouseover对象上的方法this.sup。你想要的是

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到您期望/想要的值。

于 2011-10-20T14:58:52.370 回答