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

标签 javascript oop inheritance

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

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

虽然我对这些选项中的任何一个都不太满意,但还是想出了以下选项。也可以在 https://jsfiddle.net/fpgm8j9n/ 的 fiddle 上找到.

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

以下是我发布的文章中的第一个示例。只是不必知道您的父原型(prototype),这些本质上是相同的吗?我想出的实现有什么问题或可以改进的地方吗?我对 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();

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

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

关于javascript - 这种在 javascript 中调用 super() 的方法有什么问题吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29946774/

相关文章:

javascript - 值存储在不同的数组中而不是单个数组中

oop - Go 是否支持模板或泛型?

python - 使用静态方法有什么好处?

c++ - 通过指向其非模板父类的指针将模板值分配给类模板

Java:为什么通过将子类保存为父类,子类的属性会变成父类的默认值?

java - 从父类(super class)调用方法

javascript - 如何重置按下下一个/后退按钮时自动播放幻灯片的功能?

javascript - Flot javascript 绘图 : setData for multiple series

javascript - 如何使用 Javascript/JQuery 从第 3 方站点加载 XML?

objective-c - objective-c中private和public成员应该如何实现?