【问题标题】:Is there anything wrong with this approach to calling super() in javascript?这种在 javascript 中调用 super() 的方法有什么问题吗?
【发布时间】:2015-04-29 14:32:25
【问题描述】:

我正在做一个项目,并决定实现我想要的功能的最佳方式是重写一个方法。当时我没有意识到 javascript 没有调用 super() 的概念,所以我开始做一些研究。

我发现一篇文章 (http://blog.salsify.com/engineering/super-methods-in-javascript) 描述了调用超级方法的几种方法。

不过,我对这些选项中的任何一个都不太满意,并提出了以下建议。也可以在https://jsfiddle.net/fpgm8j9n/ 的小提琴上找到。

var Food = function( name ){
    this.name = name;
}

Food.prototype.sayName = function(){
    console.log( 'I am a ' + this.name );
}

var Fruit = function( name, color ){
    Food.call( this, name );
    this.color = color;

    this.super = Object.getPrototypeOf( Object.getPrototypeOf( this ) );
}

Fruit.prototype = Object.create( Food.prototype );

Fruit.prototype.sayName = function(){
    console.log( 'I am a fruit and I am the color ' + this.color );
}

var orange = new Fruit( 'apple', 'red' );

// runs the overridden method in orange
orange.sayName(); // I am a fruit and I am the color red

// runs the super method
orange.super.sayName.call( orange ); // I am a apple

以下是我发布的文章中的第一个示例。这些本质上是否相同,而无需知道您的父原型?我提出的实现有什么问题或有什么可以改进的吗?我对 javascript 中的 OOP 还很陌生,并且对很多概念感到有点摇摆不定。

var Child = Parent.extend({
  // ...
  doSomething: function(x, y) {
    this.doSomethingElse(x);
    return Parent.prototype.doSomething.call(this, x, y);
  }
});

【问题讨论】:

标签: javascript oop inheritance


【解决方案1】:

super 的常见用例是覆盖方法调用它覆盖的方法(从而使用现有功能并使用更多代码进一步扩展它)。所以在你的例子中:

Fruit.prototype.sayName = function(){
    this.super.sayName.call(this);                 // prints "I am a apple"
    console.log( 'I am the color ' + this.color ); // prints "I am the color red"
}

var orange = new Fruit( 'apple', 'red' );
orange.sayName();

从对象的方法外部调用对象的超类方法(如orange.super.sayName.call( orange ); 中可以说是非OO 实践。对象的用户不需要知道它的类型或超类型是什么。他们应该能够要求它做某事(比如打印关于自身的信息),并且对象应该自己弄清楚如何做。

您创建的super 字段非常适合此目的,因为它允许覆盖方法调用它们覆盖的方法。但是,如果您的继承层次结构深于一层,它就会崩溃:

var Grape = function(variety) {
    Fruit.call(this, "grape", "purple");
    this.variety = variety;
};

Grape.prototype = Object.create(Fruit.prototype);

Grape.prototype.sayName = function() {
    this.super.sayName.call(this);
    console.log('I am a ' + this.variety + ' grape');
};

var concordGrape = new Grape("Concord");
concordGrape.sayName(); // unbounded recursion / causes stack overflow

原因是this.super 字段保持不变,无论层次结构的哪个级别使用它:

this                                               // Grape object
Object.getPrototypeOf(this)                        // Grape.prototype
Object.getPrototypeOf(Object.getPrototypeOf(this)) // Fruit.prototype

所以当Grape.prototype.sayName 调用this.super.sayName 时,它按预期调用Fruit.prototype.sayName。但是当Fruit.prototype.sayName 调用this.super.sayName 时,不幸的是它调用了自己。

这无法通过在每个级别重新定义 super 来解决:

var Grape = function(variety) {
    Fruit.call(this, "grape", "purple");
    this.variety = variety;
    this.super = Object.getPrototypeOf( Object.getPrototypeOf( this ) );
};

this 指向同一个对象,无论层次结构中的哪个函数引用它。

真正需要的是super 知道正在使用它的函数的层次结构级别(因此它可以从上面的级别调用相应的函数)。除了您链接的文章中的方法之外,我不知道有任何万无一失的方法。

【讨论】:

  • The user of your object should not need to know what its type or supertype are. They should just be able to ask it to do something (like print information about itself) and the object should figure out how to do that on its own. 是的。
猜你喜欢
  • 2012-04-08
  • 1970-01-01
  • 2014-06-18
  • 2011-12-08
  • 2013-06-10
  • 2010-12-30
  • 1970-01-01
相关资源
最近更新 更多