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

etc*_*tch 4 javascript oop inheritance

我正在研究一个项目并决定实现我想要的功能的最佳方法是覆盖一个方法.当时我没有意识到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
Run Code Online (Sandbox Code Playgroud)

以下是我发布的文章中的第一个例子.这些基本上是相同的,只是不必知道你的父原型?我想出的实施或任何可以改进的东西有什么问题吗?我在javascript中对OOP很新,并且对很多概念感到有些不稳定.

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

rad*_*aph 6

常见的用例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();
Run Code Online (Sandbox Code Playgroud)

从其方法外部调用对象的超类方法(因为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
Run Code Online (Sandbox Code Playgroud)

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

this                                               // Grape object
Object.getPrototypeOf(this)                        // Grape.prototype
Object.getPrototypeOf(Object.getPrototypeOf(this)) // Fruit.prototype
Run Code Online (Sandbox Code Playgroud)

因此,当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 ) );
};
Run Code Online (Sandbox Code Playgroud)

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

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