29

我读过的所有 ExtJS 文档和示例都建议像这样调用超类方法:

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

我使用这种模式已经有一段时间了,主要问题是,当你重命名你的类时,你还必须更改所有对超类方法的调用。这很不方便,我经常会忘记,然后我必须追查奇怪的错误。

但是阅读Ext.extend()我发现的源代码,我可以使用添加到原型的superclass()orsuper()方法: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 中使用过,但现在已被弃用?但它似乎是一个非常有用的功能,你为什么要弃用它?

那么,我应该使用这些方法吗?

4

6 回答 6

29

我认为这在 ExtJS 4 中通过 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]);
    }
});
于 2011-05-04T08:22:49.417 回答
14

是的,确实supr()没有记录。我一直期待在 ExtJS 3.0.0 中使用它(Ext 工作人员在论坛中回复,他们已经在那个版本中添加了它),但它似乎非常糟糕。

它目前不遍历继承层次结构,而是上一层,然后卡在这一层上,无休止地循环并炸毁堆栈(IIRC)。所以,如果你supr()连续有两个或更多,你的应用程序就会崩溃。我supr()在文档和论坛中都没有找到任何有用的信息。

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

于 2009-11-12T21:05:00.173 回答
5

这是我使用的一种模式,并且一直想在博客上讨论它。

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);

使用此模式可以获得很多功能,但您不必使用所有功能

于 2010-10-28T00:54:54.900 回答
3

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

MyApp.MyPanel = Ext.extend(Ext.Panel, {
    constructor: function() {
        // Do your thing
        this.thing = 1;

        // Call super
        arguments.callee.superclass.constructor.apply(this, arguments);
    }
});

MDC 文档

编辑:实际上,这不适用于 initComponent 因为它不是构造函数。我总是重写构造函数,个人(尽管 Ext JS 示例建议)。将继续考虑这一点。

于 2009-11-12T20:49:50.780 回答
2

我只需将您的代码更改为:

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

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

于 2011-01-10T10:13:41.367 回答
0

几个小时前我想出了这个解决方案嘿嘿......

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);
    }
});

仅使用 (Chromium 8.0.552.237 (70801) Ubuntu 10.10) 和 (Firefox 3.6.13) 测试。

希望这对某人有所帮助,我几乎要切换到 GWT。

于 2011-01-24T00:32:24.417 回答