这种在 javascript 中调用 super() 的方法有什么问题吗?

Is there anything wrong with this approach to calling super() in javascript?

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

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

虽然我对这些选项中的任何一个都不是很满意,但提出了以下选项。也可在 fiddle 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);
  }
});

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 知道使用它的函数的层次结构级别(以便它可以从上面的级别调用相应的函数)。除了您链接的文章中的方法,我不知道有什么万无一失的方法可以做到这一点。