代码改变世界

犀利的继承-再看Ext.extend

2012-02-02 23:20    阅读(158)  评论(0)    收藏  举报

忽然在一个旮旯出看见一个高人对Ext.entend有一句相当犀利的总结--Ext.extend统一了实现接口(抽象类)和继承类。

自己分析如下。

严格来说js没有类更加没有接口,这里的类和接口只是一种功能上的近似。

比如,在Ext里,想让一个自定义的类具有“添加事件的能力”,会继承Observable,从名称上看就知道Observable是一个“接口(伪)”,此时,自定义的类和Observable之间没有明显的继承关系,只是让自定义的类具有Observable的“能力”而已,此时可以称之为实现接口(抽象类)。

在严格的继承关系中,子类的构造是依赖于父类的构造的,Ext.extend也是这么做的,当走“继承”这条分支时,Ext.entend返回的是一个构造函数,而且此时构造函数是构造于父类的构造函数之上的。

Ext.extend它是如何区别你要走“继承类”路线,还是“实现接口”路线呢?

关键就是你传入第二个参数的类型。


sb(子类)sp(父类),sbp(子类的原型),spp(父类的原型)

一个典型的闭包场景,立即执行的匿名函数,实际使用的其实是,return function(sb, sp, overrides)

oc,io对外不可见

源码如下

extend : function(){
             var io = function(o){
                for(var m in o){
                    this[m] = o[m];
                }
            };
            //oc指向Object的构造函数
            var oc = Object.prototype.constructor;
            //如果第二个参数是js对象,那么走继承类路线
            //返回子类的构造函数
            return function(sb, sp, overrides){
                //经典一
                //继承类的路线
                //sb(子类),sp(父类),
                //参数的位置变换
                if(Ext.isObject(sp)){
                   //参数后移一位
                    overrides = sp;
                    sp = sb;
                   //sb被重新定义为父类的构造函数 (给子类一个默认的构造函数)
                   sb = overrides.constructor != oc ? overrides.constructor : function(){sp.apply(this, arguments);};
                }
               //经典二
               //空壳函数,为了只得到父类原型而剔除那些通过this绑定的值,
               //当继承后,
               //sb.superclass.constructor.call(this,config),父类构造函数
               //已经在子类构造函数里重新被call(父类this绑定的属性重新被子类this    绑定)
               //继承后,父类的实例属性成为子类的原型属性
               //此时成为子类原型中属性,已是多余
               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;
                }
                
                
               //给子类添加override函数 
               sb.override = function(o){
                    Ext.override(sb, o);
                };
                sbp.superclass = sbp.supr = (function(){
                    return spp;
                });
                sbp.override = io;
                //复制第二个参数到第一个参数原型对象上
                Ext.override(sb, overrides);
                sb.extend = function(o){return Ext.extend(sb, o);};
                return sb;
            };
        }(),