javascript - "this"关键字的继承和问题

标签 javascript oop inheritance this prototypal-inheritance

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

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

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

相关文章:

c# - 多态性和依赖注入(inject)

c# - 与相关类紧密耦合?

c++ - 无法让派生类使用其基类的构造函数

javascript - Paypal 快速结账 : Successful transaction but cannot show the order detail in seller account

javascript - 从ajax POST方法获取数据后,在django中打开另一个窗口

javascript - react-native-webview的方法stopLoading导致网站卡顿

Java异常处理——自定义异常

javascript - 如何将 Angular 组件与根组件分组,就像应用程序组件的工作方式一样

php - 在 PHP 中调用父级的构造函数

android - 如何使用其所有属性扩展小部件