【问题标题】:Inheritance and problems with the "this" keyword“this”关键字的继承和问题
【发布时间】:2011-12-11 20:58:47
【问题描述】:

我正在构建一个相当复杂的网络应用程序,该应用程序从用户进行初始选择的主菜单开始。这是我第一次尝试在 JavaScript 中使用继承的真正 OOP 方法,我遇到了第一个问题,即“this”关键字不是我期望的。我猜这是我的 OOP/继承方法存在更广泛问题的结果,所以我希望得到一个答案,它不仅可以告诉我如何解决这个单独的问题,还可以为我的一般方法提供更深入的反馈和建议。

我只发布 JS 代码,因为我认为 HTML 不相关,但如果有必要,我当然也可以发布。

以下代码定义了主类Select。然后它创建一个名为SelectNumSelect 的子类(查看代码末尾)。在SelectNum 中,我试图覆盖Selectmouseover 方法,但并不完全——我想先调用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() 不再抛出错误,并且运行了正确的代码。但是,我实际上需要创建一个名为SelectLevelSelectNum 子类。与覆盖其超类的mouseover() 方法的SelectNum 不同,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 对象,所以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


【解决方案1】:

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

【讨论】:

  • 谢谢。我想我更喜欢第二种方法。但是,正如您所写的,它对我不起作用。出于某种原因,typeof k 始终是string。我目前已经删除了 if 语句,因为原型只有方法/函数,而且它现在可以工作了。但是如果我需要在原型中定义属性,那么显然需要if 语句。那么我如何将它保留在那里但正确评估 k 是否是一个函数?
  • @maxedison 我有一个错误。这是typeof this.sup[k] 不是typeof k
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-12-15
  • 2017-08-25
  • 2014-02-27
  • 2015-12-04
  • 1970-01-01
  • 2014-05-28
  • 2012-09-21
相关资源
最近更新 更多