English 中文(简体)
Better way to call superclass method in ExtJS
原标题:

All the ExtJS documentation and examples I have read suggest calling superclass methods like this:

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:

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.

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. 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? But it seems such a useful feature, why would you deprecate it?

So, should I use these methods or not?

最佳回答

Yes indeed, supr() isn t documented. 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.

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). So, if you have two or more supr() in a row, your app will break. I have not found any useful information on supr() in neither the docs nor the forums.

I don t know about the maintenance releases 3.0.x, since I did not get an support license ...

问题回答

I think this is solved in ExtJS 4 with 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]);
    }
});

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

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

Edit: Actually, this isn t going to work with initComponent because it isn t the constructor. I always override the constructor, personally (despite what Ext JS examples suggest). 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. Only use $cls within your class methods and you ll be fine.

I ve came up with this solution a couple hours ago 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).

Hope this help someone, I was almost switching to GWT.





相关问题
selected text in iframe

How to get a selected text inside a iframe. I my page i m having a iframe which is editable true. So how can i get the selected text in that iframe.

How to fire event handlers on the link using javascript

I would like to click a link in my page using javascript. I would like to Fire event handlers on the link without navigating. How can this be done? This has to work both in firefox and Internet ...

How to Add script codes before the </body> tag ASP.NET

Heres the problem, In Masterpage, the google analytics code were pasted before the end of body tag. In ASPX page, I need to generate a script (google addItem tracker) using codebehind ClientScript ...

Clipboard access using Javascript - sans Flash?

Is there a reliable way to access the client machine s clipboard using Javascript? I continue to run into permissions issues when attempting to do this. How does Google Docs do this? Do they use ...

javascript debugging question

I have a large javascript which I didn t write but I need to use it and I m slowely going trough it trying to figure out what does it do and how, I m using alert to print out what it does but now I ...

Parsing date like twitter

I ve made a little forum and I want parse the date on newest posts like twitter, you know "posted 40 minutes ago ","posted 1 hour ago"... What s the best way ? Thanx.

热门标签