Properties applied via Ext.extend are shared

I should know better, but recently I extended Ext.Panel and defined the plugins array as part of the object literal.

MyKlass = Ext.extend(Ext.Panel, {
 
  plugins:['cool', 'cooler'],
 
  initComponent:function() {
    MyKlass.superclass.initComponent.apply(this, arguments);
  }
});

That’s all well and good, except there’s an important consequence to the above. As mentioned in the documentation, in reference to the second argument to Ext.extend for the two parameter signature: A literal with members which are copied into the subclass’s prototype, and are therefore shared between all instances of the new class.

In short, it means every instance of MyKlass shares a reference to the plugins array, not its own copy. That can be a problem if you need to add or remove a plugin in instances or subclasses.

If you enjoy the above pattern, you can clone the array so a pristine copy is being modified. Below I use the Ext.ux.clone extension when extending my class above. The plugins array is still shared amongst all classes and subclasses, though.

newKlass = Ext.extend(MyKlass, {
 
  addPlugin:false,
 
  initComponent:function() {
    if(this.addPlugin) {
      this.plugins = Ext.ux.clone(this.plugins||[]).concat('new-plugin');
    }
    MyKlass.superclass.initComponent.apply(this, arguments);
  }
});

Another approach is to define the array in the constructor or within initComponent itself.

MyKlass = Ext.extend(Ext.Panel, {
 
  constructor:function(config) {
    // Each instance gets its own copy now -- the prototype does not have plugins applied to it
    if(this.plugins) {
      this.plugins = this.plugins.concat('cool', 'cooler');
    }
    else {
      Ext.apply(this, {plugins:['cool', 'cooler']});
    }
    MyKlass.superclass.constructor.call(this, config);
  }
});

Strings, Numbers, and Booleans aren’t a worry.

2 Comments

  1. Scott Rouse
    Posted 3/22/2010 at 6:21 pm | Permalink

    I just hit this problem today, thank you for the workaround. I can’t seem to find much specifically about it on Extjs.com. What does Ext prescribe we do in these situation?

  2. Posted 3/22/2010 at 6:30 pm | Permalink

    The solution for object literals is to either Ext.apply({}, this.sharedConfig) or define it inside your constructor instead.

    Clearly, it’s more complicated as demonstrated above when dealing with arrays.

    I tend to prefer abusing the prototype because it’s nicer to look at. It’s easy to forget the differing behavior because strings, booleans, and integers are unaffected.

Post a Comment

Your email is never shared. Required fields are marked *

*
*