将Ext的extend继承,我大不算费很大的口舌来解释,因为真的很难表达,什么原型啦,构造函数啦等等拗口的词汇反而不会帮助我们理解,最通俗易懂的莫过于例子了。下面的例子都是模仿Ext的写法来写的,非常正轨,都是本人精心斟酌过的,是一种非常好的设计模式,希望大家既然来看了,就耐心品味下,呵呵,欢迎留言交流
下面这个例子我不打算解释,请您自己思考下
- Crab = function(){
- this.leg = 10;
- };
-
- Crab.prototype.say = function(){alert('we hava '+this.leg+'legs')};
-
- var crabObj = new Crab();
-
- crabObj.say();
引出一种类似与面向对象的设计模式
- Crab = function(){
- this.leg = 10;
-
- };
-
- Crab.prototype = {
- say : function(){alert('we hava '+this.leg+' legs');}
-
- };
-
- var crabObj = new Crab();
-
- crabObj.say();
如果你以前玩过C++,那么一定非常熟悉了。这种类的定义方式是Ext的基础所在。
var crabObj = new Crab();其实执行了2个步骤!
第一:执行this.leg = 10,其结果就是crabObj.leg = 10
第二:将Crab.prototype这个对象给了crabObj,好比crabObj.say = Crab.prototype.say;
说白了,第一步交接成员变量,第二步交接成员方法。
还有些朋友喜欢这样定义类
function Crab(){
this.leg = 10;
}
当然也是可以的
好了,这就是Ext最最普通的类的定义方式了,请接着看第二节《一个简单的继承》
有了上一节的基础,我们这一节来模拟一个简单的继承
- Crab = function(){
- this.leg = 10;
- };
- Crab.prototype.say = function(){alert('we hava '+this.leg+' legs')};
- GenCrab = function(){
- this.leg = 2;
- }
- function extend(child,father){
- child.prototype = father.prototype;
- }
- extend(GenCrab,Crab);
- gCrab = new GenCrab();
- gCrab.say();
怎么样,蟹将已经将螃蟹的方法继承下来了吧?那如果要将父类的属性也继承下来呢?我想到2个方法:
第一、把父类的属性写入prototype中,如Crab.prototype.leg = 10
第二、GenCrab.prototype = new Crab();不知道你能不能看懂,呵呵,估计网上都没有人这样用过,但这样子写能把属性和方法全部继承,其中的奥秘,请您自己思考下
好了,我们进入Ext的主题,那么Ext是怎么将属性继承下来的呢?答案是第一种方法。如果您仔细看过我写的第一篇文章,您一定会说,规范约定,只有方法才写在prototype中的呀,怎么能把属性也写入呢?岂不是把清楚的事情又弄复杂了?
聪明的Ext团队,的的确确是用第一种方法的,只是在写法上稍稍改变了下
- function extend(child,father,override){
- child.prototype = father.prototype;
-
- for(var m in override){
- child.prototype[m] = override[m];
- }
- }
这样一来,又有了新的规范了,把类的属性都往override里面写,把方法仍旧往prototype里面写,我下面举个例子
- function extend(child,father,override){
- child.prototype = father.prototype;
-
- for(var m in override){
- child.prototype[m] = override[m];
- }
- }
- Crab = function(){
-
- };
- extend(Crab,Object,{leg:10,eye:2});
- Crab.prototype.say = function(){alert('we hava '+this.leg+' legs, '+this.eye+' eyes')};
- GenCrab = function(){
- }
- extend(GenCrab,Crab,{leg:2});
- gCrab = new GenCrab();
- gCrab.say();
好了,属性和方法都已经可以继承了,Ext.extend也已经差不多成型了,请接着看第三节《Ext.extend三部曲》
这一节我们贴出Ext.extend的源代码来分析
- extend : function(){
-
- var io = function(o){
- for(var m in o){
- this[m] = o[m];
- }
- };
- return function(sb, sp, overrides){
- if(typeof sp == 'object'){
- overrides = sp;
- sp = sb;
- sb = 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 == Object.prototype.constructor){
- spp.constructor=sp;
- }
- sb.override = function(o){
- Ext.override(sb, o);
- };
- sbp.override = io;
- Ext.override(sb, overrides);
- return sb;
- };
- }(),
我们来详细说说 sbp.constructor=sb 这个东东,为什么要写这么一步呢?因为child.prototype = father.prototype这步执行好后,会把child的constructor给抹掉,所以要把它重新指回来,那么为什么一定要配上这个 constructor呢?网上有很多解释,但大都是一抄例子了事,搞了半天还是不明白有什么用处,其实constructor只是类的一个引用,当我们把一个对象调用来调用去,我们都忘记这个对象是由谁创建的时候,它就派上用场了,obj.constructor返回的就是创建obj的那个类了,明白了吧?其次,constructor还有一个方法就是反向调用,比如这样写obj.constructor.call(this),意思是用obj去调用 obj的构造方法。恩恩……非常难理解,我打算后面的章节好好介绍它的用途。
sb.superclass=spp呢?superclass又是什么?这个是Ext无中生有的一个属性而已,让子类知道它的父类是谁而已,一个标记,呵呵
综上,三部曲已经出来了吧?
第一、将属性和方法都继承下来
第二、恢复constructor,建立superclass指针
第三、将子类的属性写入到子类里
看完这3节,我想你对Ext.extend不仅有了了解,而且应该体会到Ext的编码规范,通常定义一个类,有这个三步
第一:定义Child类
Child = function(){
}
第二:Ext.extend(Child,Father,{定义Child的属性})
第三:Child.prototyp = {定义Child的方法};
或者可以只用父类和属性直接构造子类
Child = Ext.extend(Father,{});
Ext更多用这个方法,并且将方法也写入{}里面,这个方法较之上面的,多了一个神奇的第三步,见上面的代码,期间的奥秘就在于,new Child()的时候,委托谁来构造,上面是Child自己来构造,而下面这种调用方式是委托Father来构造
您照着这样的思路去看源代码定会轻松不少的:)