以下js是复制官网 Ext2.0.2版本的源码,进行的测试!
<script type="text/javascript">
/**
必备知识点:
1、通过一个类实例访问属性、方法时,进行如下搜索:一、搜索实例中的内容。二、搜索该类原型链中内容。三、向上搜索父类原型链,直到顶端父类。
2、子类和父类在原型链上的关系是StudentClass.prototype._proto_ == PersonClass.prototype,链接是通过_proto_这个属性来完成的。_proto_是一个只读的属性,只能通过构造函数写入(如3)。
3、一个对象的_proto_要指向某个构造函数的原型,需要让这个对象由那个构造函数构造,那么StudentClass.prototype = new PersonClass()就可以了,这个时候StudentClass.prototype._proto_ == PersonClass.prototype,
4、原型还有一个属性constructor指向原型所在的构造器,由于StudentClass.prototype刚被PersonClass创建出来,还没有这个属性,我们要手动赋值上去,StudentClass.prototype.constructor = StudentClass这样extend的责任就完成了。
5、Ext.extend其实并没有直接使用父类PersonClass完成继承,而是通过一个代理类F 获得PersonClass原型,完成的继承。
*/
Ext = {
version : "2.0.2"
};
/*模拟官网的apply*/
Ext.apply = function(C, D, B) {
if (B) {
Ext.apply(C, B);
}
if (C && D && typeof D == "object") {
for ( var A in D) {
C[A] = D[A];
}
}
return C;
};
/*父类*/
PersonClass = function() {
/*私有属性*/
var PName = "moline";
/*私有方法*/
var PMethod=function (){console.log(Tname);};
return {
/*公共方法:这些公共方法不在原型链上,初始化(即调用构造函数PersonClass)时返回的一个对象,它在实例对象中,属于实例中的内容。所以子类继承不了*/
getName : function() {
return PName;
},
setName : function() {
PName = arguments[0];
},
speak : function() {
console.log("person speaking!");
}
};
};
/*read和write方法在父类的原型链上,可以被子类继承*/
PersonClass.prototype.read=function (){console.log("Person read!");};
PersonClass.prototype.write=function (){console.log("Person write!");};
/*子类*/
StudentClass = function() {
/*调用父类的构造函数,将父类中的属性和方法应用到子类中,不过此处调用的不是PersonClass构造函数,而是一个空白的构造函数,即下文中的F函数*/
StudentClass.superclass.constructor.apply(this);
};
/*独立类,测试用*/
AnimalClass=function (){
};
(function() {Ext.apply(Ext,
{
/*
注1:该extend方法最终值是一个function (sb,sp,overrides),此时的extend值是一个 function (){native code}() 匿名执行函数
当Ext.apply执行copy的时候,使用了extend的值,所以 匿名执行函数 被触发并返回一个结果为包含三个参数的函数,
最终function(sb,sp,overrides)被copy到了Ext的extend的属性中,构成了extend方法。
注2:下面的io方法和oc属性,可以认为是extend方法的私有方法和属性,此处形成了一个闭包,即包含三个参数的函数引用了外部 匿名执行函数 的属性和方法。
此处的io和oc将伴随Ext对象一直存在内存中,形成以下指引关系:Ext指向extend,extend指向io和oc。
疑问1:此处形成闭包的意义,为何不让io和oc变成包含三个参数的局部变量?
疑问2:io中的this最终目的?
*/
extend : function() {
var io = function(o) {
for ( var m in o) {
this[m] = o[m];
}
};
/*保存Object的构造函数*/
var oc = Object.prototype.constructor;
return function(sb, sp, overrides) {
/*
如果是两个参数,sb是父类,sp是覆盖对象
如果三个参数,则这个if不执行,因为前两个参数应该是 子类和父 类的构造函数,类型为function
*/
if (typeof sp == "object") {
/*两个参数时,参数向后移动,sp变成父类,overrides变成覆盖对象*/
overrides = sp;
sp = sb;
/*
如果 覆盖对象 是个字面量对象,执行后面,则创建一个新的构造函数给子类,子类函数调用父类的构造函数,形成继承关系。(字面量对象没有自己的构造函数,它的构造函数指向的是Object类的构造函数)
如果 覆盖对象 不是个字面量对象,执行前面,则把覆盖对象的构造函数赋值给子类对象!一般不采取这种方式
eg:通过new创建的覆盖对象就有自己的构造函数,把这个构造函数赋值给子类即可。(覆盖对象的构造函数应该调用父类的构造函数,形成继承关系。)
最终结果:sb是一个子类构造函数,sp是父类构造函数,overrides是覆盖对象
*/
sb = overrides.constructor != oc ? overrides.constructor:function() {
sp.apply(this, arguments);
};
}
/*
F:代理类,F类原型修改为父类的原型,但没有父类的构造函数,而是一个空构造函数。
sbp:子类prototype
spp:父类prototype
*/
var F = function() {}, sbp, spp = sp.prototype;
/*F类原型修改为父类的原型*/
F.prototype = spp;
/*
完成必备知识点3,同时sbp获得子类原型
*/
sbp = sb.prototype = new F();
/*
完成必备知识点4
*/
sbp.constructor = sb;
/*子类添加superclass属性*/
sb.superclass = spp;
/*
这段代码是防御性的,在自己实现继承的时候,可能会出现原型上的构造函数指向问题,
如果父类原型的构造函数是Object的原型构造函数,则把父类构造函数sp 赋值给父类的原型构造函数
如果传递过来的父类是个构造函数,该if不执行,如果父类没有自己的构造函数而是个字面量对象,执行此if
*/
if (spp.constructor == oc) {
spp.constructor = sp;
}
/*为子类构造函数添加override方法*/
sb.override = function(o) {
Ext.override(sb, o);
};
/*为子类原型添加io方法*/
sbp.override = io;
/*终于开始了覆盖:将覆盖对象的属性或方法copy到子类的原型中*/
Ext.override(sb, overrides);
/*为子类构造函数添加extend属性,可以继续向下生成新的子类*/
sb.extend = function(o) {
Ext.extend(sb, o);
};
return sb;
};
}(),
/*实现 重写功能,必须是重写,不能新增,因为p[method]不能为未知属性 setXXX。其他版本使用apply ,可以添加*/
override : function(origclass, overrides) {
if (overrides) {
var p = origclass.prototype;
for ( var method in overrides) {
p[method] = overrides[method];
}
}
}
});
/*S 继承关系*/
var d=Ext.extend(StudentClass, PersonClass, {
/*添加的方法*/
study : function() {
return console.log("student study!");
},
/*speak不属于重写的方法,而是添加的放法*/
speak : function() {
console.log("student speak!");
},
/*重写父类的read方法*/
read:function (){
console.log("Student read!");
}
});
var stu = new StudentClass();
var per = new PersonClass();
var ani=new AnimalClass();
/*字面量对象的constructor是Object的Constructor*/
var ob = Object.prototype.constructor;
var overrides={a:1,b:function (){}};
stu.study();/*添加的方法*/
stu.speak();/*添加的方法*/
stu.read();/*重写的方法*/
stu.write();/*继承的方法*/
//stu.setName(1);/*不在原型链中,没有被继承*/
//stu.getName();/*不在原型链中,没有被继承*/
/*E 测试继承关系*/
})();
</script>