在javascript中模拟超级

Ray*_*nos 24 javascript oop super

基本上有一个很好的优雅机制来模拟super语法,就像下面的一样简单

  • this.$super.prop()
  • this.$super.prop.apply(this, arguments);

坚持的标准是:

  1. this.$super必须是原型的参考.即如果我在运行时更改超级原型,将反映此更改.这基本上意味着父母有一个新的属性然后这应该在所有孩子的运行时显示,super就像对父母的硬编码引用将反映更改
  2. this.$super.f.apply(this, arguments);必须适用于递归调用.对于任何链接的继承集,其中在继承链上进行多次超级调用时,您不能遇到递归问题.
  3. 您不得硬编码对孩子中超级对象的引用.即Base.prototype.f.apply(this, arguments);告诫这一点.
  4. 您不得使用X to JavaScript编译器或JavaScript预处理器.
  5. 必须符合ES5标准

天真的实现将是这样的.

var injectSuper = function (parent, child) {
  child.prototype.$super = parent.prototype;
};
Run Code Online (Sandbox Code Playgroud)

但这打破了条件2.

我见过的最优雅的机制是IvoWetzel的evalhack,它几乎是一个JavaScript预处理器,因此没有标准4.

hug*_*omg 10

我不认为你提到的"递归超级"问题有一种"自由"的方式.

我们不能搞砸,this因为这样做会迫使我们以非标准的方式改变原型,或者让我们向上移动原型链,失去实例变量.因此,当我们进行超级操作时,必须知道"当前类"和"超类",而不将该责任传递给this其属性或其中一个属性.

我们可以尝试做很多事情,但我能想到的都有一些不可取的后果:

  • 在创建时向函数添加超级信息,使用arguments.calee或类似的恶意访问它.
  • 调用super方法时添加额外信息

    $super(CurrentClass).method.call(this, 1,2,3)
    
    Run Code Online (Sandbox Code Playgroud)

    这迫使我们复制当前的类名(因此我们可以在一些超级字典中查找它的超类),但至少它不像复制超类名一样糟糕(因为如果更糟的话那么耦合继承关系内部耦合与类'自己的名字)

    //Normal Javascript needs the superclass name
    SuperClass.prototype.method.call(this, 1,2,3);
    
    Run Code Online (Sandbox Code Playgroud)

    虽然这远非理想,但至少有一些2.x Python的历史先例.(他们"固定"超级3.0以便它不再需要参数,但我不确定涉及多少魔法以及它对JS的可移植性如何)


编辑:工作小提琴

var superPairs = [];
// An association list of baseClass -> parentClass

var injectSuper = function (parent, child) {
    superPairs.push({
        parent: parent,
        child: child
    });
};

function $super(baseClass, obj){
    for(var i=0; i < superPairs.length; i++){
        var p = superPairs[i];
        if(p.child === baseClass){
            return p.parent;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


ngr*_*man 5

John Resig发布了一种简单而强大super支持的不一致机制.唯一的区别是super指向您调用它的基本方法.

请查看http://ejohn.org/blog/simple-javascript-inheritance/.

  • Resig代码的另一个问题.假设你有类'P`和`C`,其中`C`继承自`P`.还假设`P`和`C`都在他们的原型上定义了他们自己的`foo`和`bar`方法.最后,假设`P.foo`调用`bar`和`C.foo`调用`_super`.当调用`new C().foo()`时,调用`C.bar`,而不是`P.bar`.除非你真的很聪明,否则这是一个错误.我甚至没有尝试父类和子类方法之间的相互递归.我打赌那更糟糕的是我敢打赌它彻底打破了他的`_super`机制. (3认同)