论坛首页 Web前端技术论坛

深入剖析ExtJS 2.2实现及应用连载:Ext.extend函数的扩展

浏览 3891 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2009-01-08   最后修改:2009-02-06
Ext.extend函数的扩展

 

深入剖析ExtJS 2.2实现及应用连载  版权所有,转载标明出处和作者及版权信息

作者:彭仁夔 QQ546711211  Blog:http://www.cnblogs.com/jxnuprkhtttp://jljlpch.iteye.com

 

 

在使用Ext.extend的过程中,很多人会对很长很长的类链形式的父类中的方法的访问感觉不满。因为在Java中,我们可能通过this.supper来访问其父类的同名方法的。我们能不能有一个好的方法来解决这个问题,同时又保证Ext.extend兼容以前的类链形式的访问。

在代码3.2清单中⑤处,通过sb.superclass=spp为其静态的类注册superclass属性用来访问其父类,那么在其后加上sbp.superclass=spp;为其实例注册superclass属性能不能达上我们的要求呢?

表面上是可以的。但是细一想,如何是祖先,父亲,孩子三重继承的话,父亲通过调用this.superclass时,其得到不是祖先,而是自身。因为this是指向孩子。那怎么办呢?有没有在继承的时候就保存其对其自身的父类的引用呢?

也就是说在调用this.superclass的时候,它的superclass要改变其引用,这个改变是根据其所自身所在类而作判断的。但是superclass只是属性,调用时肯定是改不了的,如果我把this.supercalss的调用转换成this.supercalss(),那么在调用时就是运行supercalss(),这个方法在运行时找到其正确的父类。

那么现在的任务是如何实现这个supercalss()函数?要找到这个子类的父类的话,那么在继承的时候,就先在这个子类的什么地方来保存其父类的引用。什么地方呢?因为this的方式是对象方式的访问,而不是类方式的访问,保存在类中有点麻烦。

既然supercalss()是对象方式的访问,可以不可以保存在supercalss()的静态属性中呢?能这样的话,supercalss()的内部实现只要根据不同的子类而引用到这个静态属性就可以了。这里还有一个问题就是可以保证多重关系的孩子的同名静态属性不覆盖其父亲的同名静态属性?这就得采用闭包引用的原理了。

我们可以先把代码清单3.2中的return语句之前加上sbp.superclass=superclass(spp);这样每个子类的原型中都有一个自已superclass的方法(返回的是函数)。这个方法是要传入其父类的原型做为参数并将其保存在返回的函数的静态属性中。

接下来要做是根据调用这个函数的的不同类来判断啦,这个可以通过arguments.callee来引用其函数对象本身,尽管是同名的superclass,但是对于不同的层次的子类,其函数实质是完全不同的函数对象。其superclass实现如下:

代码清单3.3                                                   superclass的实现

var superclass=function(sp){

      var s=function(){ return arguments.callee.superclass; }

       s.superclass=sp;

       return s;};

上面的代码可以看出每次不同层次的子类,都是返回不同的s函数,它的函数体内容是一样的。但是其superclass是不同的。函数体中的arguments.callee就是根据this.superclass()调用来判断其是指向那个s函数。(实质上是没有判断的,因为this.superclass()就是找到当前对象的s的引用)。这一段代码放在Ext.extend()函数起始位置就可以了。

我们来看一下其测试的例子:

代码清单3.4                                                 Ext.extend扩展测试

var Animal = function() {

     alert("this is Animal constructor");

    this.name = 'animal';

    this.age = 7;

};

Animal.prototype.getAge = function() {

     alert(this.name+"'age is "+this.age);

};

Animal.prototype.getName = function() {

     alert("this is the animal Name!");

};

var Cat = Ext.extend(Animal, {

    name : 'cat',

    age : 5,

    constructor : function() {

        alert("this is Cat constructor");

       this.superclass().constructor(arguments);

    },

    getAge : function() {

       alert(this.name + "'age is " + this.age);

       this.superclass().getAge();    

    }

});

var homeCat = function() {

     alert("this is homeCat constructor");

    this.superclass().constructor(arguments);

};

Ext.extend(homeCat, Cat, {

    name : 'homeCat',

    age : 3,

    getAge : function() {      

       this.superclass().getAge();    

    }

});

var myCat = new homeCat();

myCat.getAge();

这是建立在上面扩展之后的例子,通过new homeCat(),它会依次弹出homeCat,Cat,Animal构建函数的alert的内容。调用myCat.getAge(),它也会依次弹出homeCat,Cat,Animal各自的getAgealert的内容。尽管都是通过this.superclass来调用,却还是保证其继承的关系。

这样的继承和Ext的继承是有点区别的,Ext组件树的继承都是采用如this.superclass().getXX.apply(this,arguments)的方式,每个继承链的联接都是通过apply来改变其作用域,把其所有父类中的实现方法中的this都指向当前运行的实例。

这也就是所有继承父类的this都是针对当前运行的实例进行操作,通过这样的实现,能在父类中调用子类的函数,也就是模板方法的应用。而上面扩展的继承方式则有点不同,它的this只能是指向当前类中的方法或属性。如果当前类没有的话,就会从其父类或祖先类去查找。子类对于父类中属性或方法进行了修改,这个并不会影响父类其它方法对这个属性或方法进行的调用或操作。也就是this指向是纯粹的该方法所在类的类对象。

 

   发表时间:2009-01-08   最后修改:2009-01-09
extend : function() { 
// inline overrides 
var io = function(o) { 
for (var m in o) { 
this[m] = o[m]; 
} 
}; 
var oc = Object.prototype.constructor; 
var superclass = function(sp) { 

var s = function() { 
var name = (s.caller || {}).name; 
var len = arguments.length, t = this; 
var supper = arguments.callee.superclass; 
if (!name) 
for (var n in t) { 
if (t[n] == s.caller) { 
name = n; 
break; 
} 
} 

if (len > 0 && name) { 
alert(name); 
var callArgs = Array.prototype.slice.call( 
arguments, 0); 
Array.prototype.splice.apply(callArgs, [0, 1]); 
return supper[name](callArgs); 
} 
return supper; 
} 
s.superclass = sp; 
return s; 
}; 

return function(sb, sp, overrides) { 
if (typeof sp == 'object') { 
overrides = sp; 
sp = sb; 
sb = overrides.constructor != oc 
? overrides.constructor 
: function() { 
sp.apply(this, arguments); 
}; 
} 
var F = function() { 
}, sbp, spp = sp.prototype; 
F.prototype = spp; 
sbp = sb.prototype = new F(); 
sbp.constructor = sb; 
sb.superclass = spp; 
if (spp.constructor == oc) { 
spp.constructor = sp; 
} 
sb.override = function(o) { 
Ext.override(sb, o); 
}; 
sbp.override = io; 
Ext.override(sb, overrides); 
sb.extend = function(o) { 
Ext.extend(sb, o); 
}; 
sbp.superclass = superclass(spp); 
return sb; 
}; 
}(), 
//已经溶入ExtJS使用,还没有发现问题。 


 

 

 

1 请登录后投票
   发表时间:2009-06-05  
想知道代码3.2清单在哪里?感觉楼主的文章看起来不完整。
0 请登录后投票
   发表时间:2009-06-08  
我修改了猫的继承实例如下:为何无法运行呢?使用extjs2.2.1
// JavaScript Document
var Animal = function() {
   alert("this is Animal constructor");
   this.name = 'animal';
   this.age = 7;
};

Animal.prototype.getAge = function() {
   alert(this.name + "'age is "+this.age);
};

Animal.prototype.getName = function() {
   alert("this is the animal Name!");
};

var Cat = Ext.extend(Animal, {
   name : 'cat',
   age : 5,
   constructor : function() {
      alert("this is Cat constructor");
      this.superclass().constructor(arguments);
   },
   getAge : function() {
      alert(this.name + "'age is " + this.age);
      this.superclass().getAge();
   }
});

var homeCat =Ext.extend(homeCat,Cat,{
   name : 'homeCat',
   age : 3,
   constructor : function() {
      alert("this is home cat constructor");
      this.superclass().constructor(arguments);
   },
   getAge : function() {
      alert(this.name + "'age is " + this.age);
      this.superclass().getAge();
   }
});

var myCat = new homeCat();
myCat.getAge();
0 请登录后投票
论坛首页 Web前端技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics