简体   繁体   English

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

[英]Better way to call superclass method in ExtJS

All the ExtJS documentation and examples I have read suggest calling superclass methods like this: 我读过的所有ExtJS文档和示例都建议调用这样的超类方法:

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

I have been using this pattern for quite some time and the main problem is, that when you rename your class then you also have to change all the calls to superclass methods. 我已经使用这种模式很长一段时间了,主要的问题是,当你重命名你的类时,你还必须改变所有对超类方法的调用。 That's quite inconvenient, often I will forget and then I have to track down strange errors. 这很不方便,经常我会忘记,然后我必须追查奇怪的错误。

But reading the source of Ext.extend() I discovered, that instead I could use the superclass() or super() methods that Ext.extend() adds to the prototype: 但是我读到了Ext.extend()的源代码,我发现,我可以使用Ext.extend()添加到原型的superclass()super()方法:

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

In this code renaming MyPanel to something else is simple - I just have to change the one line. 在这个代码中,将MyPanel重命名为其他东西很简单 - 我只需更改一行。

But I have doubts... 但我怀疑......

  • I haven't seen this documented anywhere and the old wisdom says, I shouldn't rely on undocumented behaviour. 我没有在任何地方看到过这种情况,旧的智慧说,我不应该依赖于无证件的行为。

  • I didn't found a single use of these superclass() and supr() methods in ExtJS source code. 我没有在ExtJS源代码中单独使用这些superclass()supr()方法。 Why create them when you aren't going to use them? 为什么在你不打算使用它们时创建它们?

  • Maybe these methods were used in some older version of ExtJS but are deprecated now? 也许这些方法在某些旧版本的ExtJS中使用但现在已被弃用? But it seems such a useful feature, why would you deprecate it? 但它似乎是一个非常有用的功能,你为什么要弃用呢?

So, should I use these methods or not? 那么,我应该使用这些方法吗?

I think this is solved in ExtJS 4 with callParent. 我认为这是使用callParent在ExtJS 4中解决的。

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

Yes indeed, supr() isn't documented. 是的, supr()没有记录。 I've been looking forward to using it in ExtJS 3.0.0 (an Ext staff member replied in the forums, they had added it in that version), but it seems horribly broken. 我一直期待在ExtJS 3.0.0中使用它(一个Ext工作人员在论坛中回复,他们已经在该版本中添加了它),但它看起来非常糟糕。

It currently does not traverse the inheritance hierarchy, but rather go up one level, then gets stuck on this level, loops endlessly and blows up the stack (IIRC). 它目前不会遍历继承层次结构,而是上升到一个级别,然后卡在这个级别上,无休止地循环并炸毁堆栈(IIRC)。 So, if you have two or more supr() in a row, your app will break. 因此,如果您连续两个或更多supr() ,您的应用程序将会中断。 I have not found any useful information on supr() in neither the docs nor the forums. 我没有在文档和论坛中找到有关supr()任何有用信息。

I don't know about the maintenance releases 3.0.x, since I did not get an support license ... 我不知道维护版本3.0.x,因为我没有获得支持许可证...

Here's a pattern I use, and been meaning to blog about it for a while. 这是我使用的模式,并且有一段时间的博客意义。

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

There are a lot of features you get using this pattern, but you don't have to use all of them 使用此模式可以获得许多功能,但您不必使用所有这些功能

You could use this little known Javascript feature ( arguments.callee ): 您可以使用这个鲜为人知的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);
    }
});

see MDC documentation 请参阅MDC文档

Edit: Actually, this isn't going to work with initComponent because it isn't the constructor. 编辑:实际上,这不适用于initComponent,因为它不是构造函数。 I always override the constructor, personally (despite what Ext JS examples suggest). 我总是个人覆盖构造函数(尽管Ext JS的例子建议)。 Will continue to think about this one a bit. 将继续考虑这一点。

I would simply change your code to: 我只想将您的代码更改为:

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

That way you only keep a single reference of your class name, now $cls. 这样你只需保留一个类名的引用,现在是$ cls。 Only use $cls within your class methods and you'll be fine. 只在你的班级方法中使用$ cls,你会没事的。

I've came up with this solution a couple hours ago heheh... 我几个小时前想出了这个解决方案heheh ......

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

Then you can do: 然后你可以这样做:

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

Tested only with (Chromium 8.0.552.237 (70801) Ubuntu 10.10) and (Firefox 3.6.13). 仅使用(Chromium 8.0.552.237(70801)Ubuntu 10.10)和(Firefox 3.6.13)进行测试。

Hope this help someone, I was almost switching to GWT. 希望这有帮助的人,我几乎转向GWT。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM