2

我想[Parent].f()从内部[Child].g()而不是[Child].f().

假设我有 MooTools 代码:

var Parent = new Class({
    f: function () {
        console.log('Parent.f()');
    }
});

var Child = new Class({
    Extends: Parent,

    f: function () {
        console.log('Child.f()');
    },

    g: function () {
        // Call Parent.f()
        this.parent.f();
    }
});

var o = new Child();

o.g();

显然this.parent.f()是无稽之谈,因为 MooTools 使this.parent父类的方法与您所在的方法同名,即在Child.g()此将是Parent.g().

那么,我该怎么打电话P.f()呢?

4

2 回答 2

3

您遇到的问题是Child hasOwnProperty f,因此调用child.f()将在实例而不是原型上获取它。

与其按照其他答案中的建议进行切换this.$caller.$name,不如直接从父原型中调用它:

this.$constructor.parent.prototype.f.call(this);
// or
this.$constructor.parent.prototype.f.apply(this, arguments);

当然,如果你不关心 Reflection-ish,你可以这样做P.prototype.f.call(this)- 但它是非 DRY 的,因为这意味着该方法需要知道超级的名称。

这种方法的问题在于,如果 Parent 正在扩展另一个父级等等,它是否会起作用,但在大多数情况下应该没问题。如果 Child 没有父级或没有父级,它也会失败f,在逻辑上它应该恢复运行自己的f.

var Parent = new Class({
    f: function(msg){
        console.log('Parent.f() says ' + msg);
    }
});

var Child = new Class({
    Extends: Parent,
    f: function(){
        console.log('Child.f()');
    },   
    g: function(){
        // Call Parent.f()
        this.$constructor.parent.prototype.f.apply(this, arguments);
    }
});

new Child().g('hello');

如果您需要经常这样做,您可以在父类上创建一个新方法作为 mixin。例如。

Class.parenting = new Class({
    // mixin class that allows call
    _parent: function(method, args){
        this.$constructor.parent.prototype[method].apply(this, args);    
    }.protect() // private, restricted to methods
});

var Parent = new Class({
    Implements: [Class.parenting],
    f: function(msg){
        console.log('Parent.f() says ' + msg);
    }
});

var Child = new Class({
    Extends: Parent,
    f: function(){
        console.log('Child.f()');
    },   
    g: function(){
        this._parent('f', arguments);
    }
});

var c = new Child();
c.g('hello');
c._parent('f'); // throws, only instances methods can call this
于 2013-11-15T10:46:03.227 回答
0

通过查看 MooTools 代码可以找到一种非常快速且令人讨厌的方法,但是它可能会在较新版本的 MooTools 上中断。

它通过设置this.$caller.$name您要调用的方法并在调用后重置它来工作。

    g: function () {
         var oldName = this.$caller.$name;
         this.$caller.$name = 'f';

         try {
             this.parent(...);
         } catch (e) {
             this.$caller.$name = oldName; // Ensure name is always reset
             throw e;
         }

         this.$caller.$name = oldName;
     }
于 2013-11-15T09:46:33.247 回答