在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;
}
}
},