Ext.extend 源码分析

在Ext.extend中混合使用了两种继承手段:原型集成和对象冒充。

原型集成主要表现在:

                var F = function(){},
                    sbp,
                    spp = sp.prototype;

                F.prototype = spp;
                sbp = sb.prototype = new F();
                //将子函数sb的构造函数指回去
                sbp.constructor=sb;

对象冒充主要表现在:1、var Person = Ext.extend(Animal, {...});或者 var Person = Ext.extend(Animal, {constructor: function(){....}};情况调用下的:

sb = overrides.constructor != oc ? overrides.constructor : function(){sp.apply(this, arguments);};
2、Person = function(){

          Person.superclass.constructor.call(this, {....});

};

Ext.extend(Person, Animal, {...});


上面只是简单的对Ext.extend的实现做了简单的描述,如果不明白,请看下面对源码的详细解析,如果哪位觉得有更好的解释或者不对的地方,欢迎批评指正

        //在本方法中使用了闭包以及自执行,当浏览器加载js时就会执行该函数,然后将return的对象返回出来
        extend : function(){
            // inline overrides
        	//私有变量,对外不可调用
            var io = function(o){
                for(var m in o){
                    this[m] = o[m];
                }
            };
            var oc = Object.prototype.constructor;

            return function(sb, sp, overrides){
            	/**
            	 * 主要用做移位,例如以下两种写法:
            	 * 1、var Person = Ext.extend(Animal, {
            	 * 						name: 'huang',
            	 *						//如果子类提供了自己的构造方法,则使用自己提供的构造方法(overrides.constructor),
            	 *						//否则则使用则会赋值给一个函数:function(){sp.apply(this, arguments);
            	 *						//如果子类没有提供自己的构造方法,使用apply调用父类的构造函数,将父类中通过this赋值的属性继承下来,
            	 *						//但是父类的prototype上的属性不会被继承下来(对象冒充),对于父类静态的属性不会被继承下来
            	 * 						constructor: function(){...}
            	 * 					});
            	 * 2、Ext.extend(Person, Animal, {...});
            	 * 
            	 * 如果使用第二种方式那么if条件肯定是不成立的,也就不会给子类设置一个默认的构造函数,而是使用我们自己提供的构造函数Person进行
            	 * 对象的构造,正因为如此,此时也享受不到Ext默认插入的这句调用:sp.apply(this, arguments);所以需要获得父类的实例属性和方法,
            	 * 需要在构造函数中手动加入对象的冒充操作:Person.superclass.constructor.call(this, config);
            	 */
                if(Ext.isObject(sp)){
                    overrides = sp;
                    sp = sb;
                    sb = overrides.constructor != oc ? overrides.constructor : function(){sp.apply(this, arguments);};
                }
                /**
                 * 这里的亮点是空函数,因为空函数里面没有通过this进行赋值的属性,因此将sp.prototype 赋值给F.prototype
                 * 然后将new F()赋值给sb.prototype,保证了sbp的纯净性
                 */
                var F = function(){},
                    sbp,
                    spp = sp.prototype;

                F.prototype = spp;
                sbp = sb.prototype = new F();
                //将子函数sb的构造函数指回去
                sbp.constructor=sb;
                /**
                 * 给子函数sb赋属性superclass,并指向sp.prototype,自定义一个属性来记录子类的父类是什么
                 * 这样就可以直接调用  sb.superclass.constructor.call(this, xxx)了;
                 */
                sb.superclass=spp;
                /**
                 * 这是一个容错处理,防止父类的构造函数没有指正确,
                 * 这里也是主要为了在子类中调用sb.superclass.constructor.call(this, xxx)做准备
                 * 例如:Animal = function(cfg){
		 *			this.name = "dog";
		 *			Ext.apply(this, cfg);
		 *		}
		 *		Animal.prototype = {
		 *			eat: function(){
		 *				alert("animal eat");
		 *			}
		 *		}
		 *		//如果下面这一句没有写,spp.constructor 就会指向一个object
		 *  	Animal.prototype.constructor = Animal;
                 */
                if(spp.constructor == oc){
                    spp.constructor=sp;
                }
                sb.override = function(o){
                    Ext.override(sb, o);
                };
                sbp.superclass = sbp.supr = (function(){
                    return spp;
                });
                sbp.override = io;
                /**
                 * 此处将overrides上的属性全都copy到了sb.prototype上,因此如下面的写法:
                 * Animal = function(){
                 * 		this.name = "dog";
                 * }
                 * Animal.prototype = {...};
                 * Person = function(){
                 * 		this.sex = "boy";
                 * }
                 * Ext.extends(Person, Animal, {
                 * 		name: "kk"
                 * });
                 * var p = new Person();
                 * p.alert(p.name);
                 * 这样写也出来的结果是:dog,而不是kk,因为name:kk在prototype上,原型查找机制,对象上直接有的属性优先
                 * 而如果var p = new Person({name: 'huang'});执行结果则是:huang
                 */
                Ext.override(sb, overrides);
                sb.extend = function(o){Ext.extend(sb, o);};
                return sb;
            };
        }(),

        override : function(origclass, overrides){
            if(overrides){
                var p = origclass.prototype;
                Ext.apply(p, overrides);
                if(Ext.isIE && overrides.toString != origclass.toString){
                    p.toString = overrides.toString;
                }
            }
        },



©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页