Javascript 在ExtJS中调用超类方法的更好方法

Javascript 在ExtJS中调用超类方法的更好方法,javascript,extjs,extend,extjs3,superclass,Javascript,Extjs,Extend,Extjs3,Superclass,我读过的所有ExtJS文档和示例都建议调用超类方法,如下所示: MyApp.MyPanel = Ext.extend(Ext.Panel, { initComponent: function() { // do something MyPanel specific here... MyApp.MyPanel.superclass.initComponent.call(this); } }); 我已经使用这个模式很长一段时间了,主要的问题是,当你重命名你的类时,你还必须改

我读过的所有ExtJS文档和示例都建议调用超类方法,如下所示:

MyApp.MyPanel = Ext.extend(Ext.Panel, {
  initComponent: function() {
    // do something MyPanel specific here...
    MyApp.MyPanel.superclass.initComponent.call(this);
  }
});
我已经使用这个模式很长一段时间了,主要的问题是,当你重命名你的类时,你还必须改变所有对超类方法的调用。这很不方便,通常我会忘记,然后我不得不追踪奇怪的错误

但是阅读
Ext.extend()
的源代码时,我发现我可以使用
superclass()
super()
方法,而
Ext.extend()

MyApp.MyPanel = Ext.extend(Ext.Panel, {
  initComponent: function() {
    // do something MyPanel specific here...
    this.superclass().initComponent.call(this);
  }
});
在这段代码中,将MyPanel重命名为其他名称很简单-我只需更改一行即可

但我有疑问

  • 我在任何地方都没有看到这方面的记录,古老的观点认为,我不应该依赖未记录的行为

  • 我在ExtJS源代码中没有发现这些
    superclass()
    supr()
    方法的一次使用。当你不打算使用它们的时候,为什么还要创建它们呢

  • 也许这些方法在一些旧版本的ExtJS中使用过,但现在不推荐了?但它似乎是一个非常有用的功能,为什么您会反对它呢


那么,我是否应该使用这些方法呢?

您可以使用这个鲜为人知的Javascript功能(arguments.callee):

编辑:实际上,这不适用于initComponent,因为它不是构造函数。我个人总是重写构造函数(不管ExtJS示例如何建议)。我会继续考虑这个问题。

是的,确实,
supr()
没有文档记录。我一直期待在ExtJS 3.0.0中使用它(一名Ext工作人员在论坛上回复,他们在该版本中添加了它),但它似乎坏得可怕

它目前不遍历继承层次结构,而是上一级,然后停留在这个级别上,无休止地循环并炸毁堆栈(IIRC)。因此,如果您有两个或两个以上的
supr()
,您的应用程序将中断。我在文档和论坛中都没有找到任何关于
supr()
的有用信息


我不知道3.0.x版的维护版本,因为我没有获得支持许可证…

这是我使用的一种模式,我打算在博客上写一段时间

Ext.ns('MyApp.MyPanel');

MyApp.MyPanel = (function(){
  var $this = Ext.extend(Ext.Panel, {
    constructor: function() {
        // Using a 'public static' value from $this
        // (a reference to the constructor)
        // and calling a 'private static' method
        this.thing = $this.STATIC_PROP + privateStatic();
        // Call super using $super that is defined after 
        // the call to Ext.extend
        $super.constructor.apply(this, arguments);
    },
    initComponent: function() {
        $super.initComponent.call(this);
        this.addEvents([Events.SOMETHING]); // missing docs here
    }
  });
  var $super = $this.superclass;

  // This method can only be accessed from the class 
  // and has no access to 'this'
  function privateStatic() {
    return "Whatever";
  }


  /** 
    * This is a private non-static member
    * It must be called like getThing.call(this);
    */
  function getThing() {
     return this.thing;
  }

  // You can create public static properties like this
  // refer to Events directly from the inside
  // but from the outside somebody could also use it as
  //  MyApp.MyPanel.Events.SOMETHING
  var Events = $this.Events = {
      SOMETHING: 'something'
  }

  return $this;
})();

MyApp.MyPanel.STATIC_STRING = 10;

//Later somewhere
var panel = new MyApp.Mypanel();
panel.on(MyApp.Mypanel.Events.SOMETHING, callback);

使用此模式可以获得许多功能,但您不必全部使用它们

我只需将代码更改为:

var $cls = MyApp.MyPanel = Ext.extend(Ext.Panel, {
  initComponent: function() {
    // do something MyPanel specific here...
    $cls.superclass.initComponent.call(this);
  }
});

这样,您只保留一个类名称引用,现在是$cls。只要在类方法中使用$cls,您就可以了。

我几个小时前就提出了这个解决方案,呵呵

function extend (parentObj, childObj) {
    parentObj = parentObj || function () {};

    var newObj = function () {
        if (typeof this.initialize == 'function') {
            this.initialize.apply(this, arguments);
        }
    }

    newObj.prototype.__proto__ = parentObj.prototype;

    for (var property in childObj) {
        newObj.prototype[property] = childObj[property];
    }

    newObj.prototype.superclass = function (method) { 
        var callerMethod = arguments.callee.caller,
            currentProto = this.constructor.prototype.__proto__;

        while (callerMethod == currentProto[method]) {
            currentProto = currentProto.__proto__;
        } 

        return currentProto[method]; 
    };

    return newObj;
}
然后你可以做:

var A = function () { 
    this.name = "A Function!";
};

A.prototype.initialize = function () {
    alert(this.name);
}

var B = extend(A, {
    initialize: function () {
        this.name = "B Function!";
        this.superclass('initialize').apply(this);
    }
});

var C = extend(B, {
    initialize: function () {
        this.superclass('initialize').apply(this);
    }
});
仅使用(铬8.0.552.237(70801)Ubuntu 10.10)进行测试 和(Firefox 3.6.13)


希望这能对其他人有所帮助,我几乎要换成GWT了。

我想这在ExtJS4中通过callParent解决了

Ext.define('My.own.A', {
    constructor: function(test) {
        alert(test);
    }
});

Ext.define('My.own.B', {
    extend: 'My.own.A',

    constructor: function(test) {
        alert(test);

        this.callParent([test + 1]);
    }
});

JavaScript 1.4:已弃用被调用方作为Function.arguments的属性,保留它作为函数的局部arguments变量的属性。不一样!啊,对不起,你说得对。我把它和完全不赞成的“来电者”混淆了。删除被调用方会很混乱。实际上,您可以尝试
this.constructor.superclass.initComponent.call(this)?谢谢,但这与Jabe描述的问题相同-它只适用于一个层次结构级别。谢谢,它确实不适用于多个继承层次结构级别。仅供参考:在3.0.3中,在这方面没有任何变化。Sencha Touch 1.1Nice仍然是这样,但这种方法引入了大量样板代码,如果调用许多父类方法,这可能很好,但我通常只需要调用initComponent()的父类,其他什么都不需要,在这种情况下,额外的代码是不值得的。是的,这种模式适用于所有使用继承的OO代码,您可以调用父方法。在Ext中,我经常从父级调用onRender、afterRender、beforeDestroy,因为我覆盖了它。这太棒了,谢谢!我特别喜欢这个,因为如果操作正确,它可以通过JSLint/测试。我在linting方面遇到了一些问题。@ReneSaarsoo,您(或Juan Mendes)如何在这种设计中保留非静态私有方法?@b.long最简单的解决方案是让您的私有非静态函数只使用类似于
privateStatic
的函数,但您必须使用
privateNonStatic.call调用(this,arg1,arg2)
。不是很优雅…如果我将每个类包装在一个闭包中,这个解决方案就可以工作了。目前我没有,所以这个解决方案不起作用。也许有一天我会的,所以这可以成为可行的。
函数、调用者
对象.\uuuuu协议.\uuuu
都是非标准的。此外,后者也不推荐使用。不过,这个想法看起来很有趣。这个问题与ExtJS3.x有关(供稍后可能阅读本文的用户使用)
Ext.define('My.own.A', {
    constructor: function(test) {
        alert(test);
    }
});

Ext.define('My.own.B', {
    extend: 'My.own.A',

    constructor: function(test) {
        alert(test);

        this.callParent([test + 1]);
    }
});