欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

来贴存根: 理解Ext.extend函数 3.1

程序员文章站 2022-07-14 17:50:33
...
今天群里有人闻起来, 找了半天, 特地将以前稿子存根



首先感谢LZ的分析, 站在LZ的基础上, 我自己也分析了一遍, 希望大家能更明白.
extend : function(){
	// inline overrides, 临时函数用于覆盖属性到this上.
	var io = function(o){
		for(var m in o){
			this[m] = o[m];
		}
	};
	var oc = Object.prototype.constructor; //保留Object的构造器的引用.

	//上面的部分为Ext.extend函数的私有变量区, 使用闭包.
	//下面的部分是Ext.extend调用者实际调用的函数.
	return function(sb, sp, overrides){
		/**
		 * 在这个if语句中完成了对Ext.extend方法的重载. Ext.extend有两种调用方式.
		 * 1. var Subclass = function(){...};
		 *    Ext.extend(Subclass, Superclass, {...});
		 * 2. var Subclass = Ext.extend(Superclass, {...});
		 * 
		 * 方式1和方式2的不同在于, 参数顺序的错位. 其中子类的引用在方式2中没有, 导致原本在2,3位置的父类
		 * 和属性集变成了1,2位.
		 * 为了屏蔽两种调用方式的差异, if(Ext.isObject(sp)) 用来判断2号参数的类型, 如果不是"Object"
		 * 类型就是第一种调用方式, 否则就是第二种调用方式.
		 * 当知晓是第二种调用方式之后, 需要修正参数的位置, 于是出现了一下两个语句:
		 * overrides = sp; //修正3号参数(原2号)
		 * sp = sb; //修正2号参数(原1号)
		 * 那么空出来的1号参数怎么办呢? sb对应第一种调用方式应该是子类引用. 
		 * 而第二种的子类引用正是Ext.extend返回的.
		 * 所以这里就给了一个默认的构造函数给子类.(这也是1,2两种方式的不同: 是否自定义构造函数.)
		 * 默认的构造函数的内容就是在子类对象的作用域内调用父类的构造函数, 即获取父类的非原型属性(当然
		 * 这个获取的过程是new子类对象时产生的, 而现在只是产生了这个能够调用父类函数的引用作为子类
		 * 的构造函数).
		 * 自此, 两种方式的重载完成修正, 下面可以正常的按照3个参数(即第一种方式)建立继承关系.
		 */
		if(Ext.isObject(sp)){
			overrides = sp;
			sp = sb;
			sb = overrides.constructor != oc ? overrides.constructor : function(){sp.apply(this, arguments);};
		}
		
		/**
		 * 上面说到了子类的构造方法能够获取父类的非原型属性, 那么最关键的父类原型的内容就在下面.
		 * 值得注意的是: 要准确的区分静态属性(方法)与实例属性(方法).
		 * 静态属性(方法)指的是类(构造器)的直接属性(方法), 这里就是sb.[...]. 这种方式书写, 不会作为
		 * 对象的属性(方法), 只能通过类的引用(类名)来访问.
		 * 实例属性(方法)指的是类(构造器)原型对象的属性(方法), 这里就是sbp.[...]. 这种方式的
		 * 属性(方法)才会被对象(实例)所拥有.
		 * 同样, 构造器函数内部定义的, 附加到this之上的属性也是实例属性(方法).
		 */
		//这里建立一个空函数F是去除父类的非原型属性, 防止多拷贝一次非原型属性, 影响性能.
		var F = function(){}, 
			sbp,	//子类原型的引用. subclass-prototype 的缩写.
			spp = sp.prototype;	//父类原型的引用. superclass-prototype 的缩写

		F.prototype = spp;
		//获取在父类原型基础上产生的对象作为子类原型, 这里建立了原型继承关系.
		sbp = sb.prototype = new F(); 
		sbp.constructor=sb; //修正子类的构造函数指向子类(原本指向F, 因为是new F()出来的原型.
		sb.superclass=spp; //设置子类引用父类原型对象, 静态属性.
		if(spp.constructor == oc){ //这里修正了下父类的构造函数, 若为Object就扭转到自身.
			spp.constructor=sp;
		}
		//子类的override静态方法, o为属性集, 用于覆盖原本的子类原型的属性.
		sb.override = function(o){ 
			Ext.override(sb, o);
		};
		//子类的实例方法, 可以获取到父类原型的引用.
		sbp.superclass = sbp.supr = (function(){	
			return spp;
		});
		//子类的实例方法, 覆盖对象的属性. 实际上此方法依赖js的动态语言特性实现.
		sbp.override = io; 
		//最后, 将继承时需要的属性(方法)覆盖到子类的原型, 即增加/修改了子类的实例属性(方法).
		Ext.override(sb, overrides); 
		sb.extend = function(o){return Ext.extend(sb, o);};
		return sb;
	};
}(),

相关标签: extjs 3.1