【问题标题】:Proper way to call superclass functions from subclass从子类调用超类函数的正确方法
【发布时间】:2014-05-29 10:40:10
【问题描述】:

我有一个带有“info”作为实例变量的“SuperClass”。 “SuperClass”具有函数“printInfo()”。 “printInfo()”需要访问实例变量“info”。 我想创建一个“子类”,它也有方法“printInfo()”。我想从“SubClass”的“printInfo()”中调用“SuperClass”的printInfo()。

SuperClass = function()
{
    this.info = "I am superclass";
    console.log("SuperClass:");
};

SuperClass.prototype.printInfo = function(that)
{
    console.log("printing from superclass printInfo");
    console.log(that.info);
};

SubClass = function(){};

SubClass.prototype = new SuperClass();

SubClass.prototype.printInfo = function()
{
    console.log("calling superclass");
    this.constructor.prototype.printInfo(this);
    console.log("called superclass");
};

var sc = new SubClass();
sc.printInfo();

您可以看到我将“that”作为参数传递给 printInfo。如果没有“that”参数,“info”将打印为“undefined”。像下面的例子一样,当从“子类”的对象调用这个函数时,“this.info”是未定义的。

SuperClass.prototype.printInfo = function()
    {
        console.log("printing from superclass printInfo");
        console.log(this.info);
    };

在javascript中覆盖和调用超类方法的正确方法是什么,使函数能够访问类的实例变量?

【问题讨论】:

标签: javascript inheritance prototypal-inheritance


【解决方案1】:

你可以这样写:

SuperClass.prototype.printInfo = function(){
  console.log("printing from superclass printInfo");
  console.log(this.info); 
};

SubClass.prototype.printInfo = function(){
  console.log("calling superclass");
  SuperClass.prototype.printInfo.call(this);
  console.log("called superclass");
};

【讨论】:

    【解决方案2】:

    在这一行中,您正在用SuperClass 的对象弄乱SubClass 的原型

    SubClass.prototype = new SuperClass();
    

    孩子的原型应该依赖于父母的原型。所以,你可以这样继承

    SubClass.prototype = Object.create(SuperClass.prototype);
    

    另外,把构造函数改成实际的函数是很正常的,像这样

    SubClass.prototype.constructor = SubClass;
    

    为了保持你的实现通用,你可以使用Object.getPrototypeOf,获取继承链中的父原型,然后调用printInfo,像这样

    SubClass.prototype.printInfo = function() {
        Object.getPrototypeOf(SubClass.prototype).printInfo(this);
    };
    

    由于info 是在SubClass 中定义的,所以它将打印undefined。您可能还想调用父级的构造函数,像这样

    var SubClass = function() {
        SuperClass.call(this);
    };
    

    注意:您正在创建全局变量,方法是在 SuperClassSubClass 之前省略 var 关键字。

    【讨论】:

    • 为了保持通用性,我用 Object.getPrototypeOf(Subclass.prototype).constructor.call(this) 调用了超级构造函数。这与调用超类函数的方式相同。虽然我不确定这是否正确,但我不是 js 工作原理的专家。
    • Subclass.printInfo()Superclass.printInfo() 的呼叫不会是Object.getPrototypeOf(SubClass.prototype).printInfo.call(this) 而不仅仅是...printInfo(this)? 我这样问是因为我按照你的方式尝试了,但遇到了关于undefined 的错误。我不是 JS 专家,所以我不清楚为什么任何一种方式都行得通。
    • @thefourtheye 如果你想真正干净,可以说Object.getPrototypeOf(Object.getPrototypeOf(this))
    • @GreatBigBore 正确。您需要.call(this),以便被调用方法内部的this 与调用方法内部相同。
    【解决方案3】:

    看完所有答案后,我使用的继承机制如下:

    var SuperClass = function()
    {
        this.info = "I am superclass";
        console.log("SuperClass:");
    };
    
    SuperClass.prototype.printInfo = function()
    {
        console.log("printing from superclass printInfo");
        console.log("printinfo");
        console.log(this.info);
    };
    
    var SubClass = function(){
        SuperClass.call(this);
    };
    
    SubClass.prototype = Object.create(SuperClass.prototype);
    SubClass.prototype.constructor = SubClass;
    
    SubClass.prototype.printInfo = function()
    {
        console.log("calling superclass");
        Object.getPrototypeOf(SubClass.prototype).printInfo.call(this);
        console.log("called superclass");
    };
    
    var sc = new SubClass();
    sc.printInfo();
    

    【讨论】:

    • 你也需要设置构造函数,SubClass.prototype.constructor = SubClass
    【解决方案4】:

    @coolscitist

    代替

    SubClass.prototype.printInfo = function()
    {
        Object.getPrototypeOf(SubClass.prototype).printInfo.call(this);
    };
    

    使用这个

    SubClass.prototype.printInfo = function()
    {
        Object.getPrototypeOf(this.constructor.prototype).printInfo.call(this);
    };
    

    【讨论】:

    • 谢谢。只有你的解决方案对我有用。其他答案调用超类方法正常,但得到未定义的“this”错误。
    • 不,这样不行。假设一个新类Class3 继承自SubClass,调用Class3 的printInfo() 将导致无限循环。这是因为上面的this.constructor总是会给出Class3而不是SubClass,即一次又一次地调用Class3的超类(子类)的printInfo函数。
    【解决方案5】:

    对于更多来自 Java 世界的人,我会忽略以上所有内容并使用以下语法,而不是 2015 年引入的语法

    class Polygon {
      constructor(height, width) {
        this.height = height;
        this.width = width;
      }
    }
    
    class Square extends Polygon {
      constructor(sideLength) {
        super(sideLength, sideLength);
      }
      get area() {
        return this.height * this.width;
      }
      set sideLength(newLength) {
        this.height = newLength;
        this.width = newLength;
      }
    } 
    

    更多信息https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain

    突然间你可以使用 super 作为关键字来访问祖先等......对我来说发现这是一个很大的解脱

    【讨论】:

    • 正是我想要的。
    • 很遗憾,super 只能在构造函数中使用。
    • 幸运的是,@Offirmo 是错误的。 :-) 请参阅下面的答案。
    【解决方案6】:
    class Thing {
      constructor(age) { this.age = age; }
      die(how) { console.log(`Died of ${how}`); }
    }
    
    class Me extends Thing {
      constructor() { super(59); console.log(`I am ${this.age}`); }
      // Refer to a method from the superclass that is overridden in the subclass
      die(how) { super.die('liver failure'); console.log(`while ${how}`) }
    }
    
    (new Me()).die('hang gliding');
    

    【讨论】:

    • 这正是我想要的。谢谢!
    • 这应该是公认的答案。简单并使用新的class 语法
    【解决方案7】:

    我能够解决这个问题的唯一方法是在覆盖子类定义之前将父函数保存在不同的变量中。

    var Foo = function(){
        var self = this.
        this.init = function(a,b){
            self.a = a;
            seld.b = b;
        };
    }
    
    var Goo = function(){
        Foo.apply(this);
        var self = this;
        self.Foo = { init: self.init };//saves the super class's definition of init in a new variable
        self.init = function(a,b,c){
           self.Foo.init(a,b);//can call the super class function
           self.c = c;
        };
    }
    
    var a = new Foo();
    a.init(1,2);
    var b = new Goo();
    b.init(1,2,3);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-05-27
      • 2016-01-22
      • 2011-10-24
      • 2012-04-18
      • 1970-01-01
      相关资源
      最近更新 更多