日期:2014-05-16 浏览次数:20473 次
接着第四章....
这两个方法是对外提供的扩展接口,可以用declare出来的类型的实例调用。它们的用途是返回父类中曾经出现的方法,或者对其进行调用。具体的用法在第二章中已经描述,这里不再举例说明。
1. getInherited方法主要用来返回父类中的方法;
2. inherited方法主要用来调用父类中的方法;
首先来看getInherited方法,该方法的实现比较简单:
//getInherited的实现,调用了inherited
function getInherited(name, args){
//如果传入name,则返回指定name的方法
if(typeof name == "string"){
return this.inherited(name, args, true);
}
//否则返回的是父类中的同名方法
return this.inherited(name, true);
}
上面的实现中可以看出,在getInherited中其实还是调用inherited来做进一步处理,只不过将inherited的最后一个参数设置为true,在inherited里会判断该参数,为true就是返回函数,不为true则是调用函数。
?
接下来看inherited方法,可以分成个3步骤依次来看inherited具体的实现细节。第一步 依然是crack arguments,这是由于dojo提供的API的灵活性所致,就要求这样也能调用,那样也能调用,很蛋疼。第二步 就是根据name参数来寻找父类中的同名方法,这里的name有可能是constructor,也就是说我们可以利用inherited去调用父类中的构造函数,因此在inherited的实现里做了分情况讨论,一种情况是调用父类的非构造函数,还有一种是调用构造函数。想想在第三章末尾曾讲述过,可以把某继承链的构造器调用顺序设置为manual,这样将会破坏默认的自动调用父类构造函数,用户可以根据自己手动去调用父类的构造函数,用的正是this.inherited('constructor',arguments)....在第二步完成之后,第三步 所做的工作很简单,即决定是返回找到的同名方法还是调用这个同名方法。
function inherited(args, a, f){
var name, chains, bases, caller, meta, base, proto, opf, pos,
cache = this._inherited = this._inherited || {};
// 首先是crack arguments
// 最后传入的参数f可能是true,也可能是一个替代args的数组,还有可能是默认的undefined
if(typeof args == "string"){
name = args;
args = a;
a = f;
}
f = 0;
//args是子类方法的参数列表,args.callee代表在子类的哪个方法中调用了inherited
caller = args.callee;
//获取欲调用的父类的方法的名称,如果没有传入name参数,那么就是调用父类中的同名方法
name = name || caller.nom;
if(!name){
err("can't deduce a name to call inherited()");
}
//这里获取到的是子类型的meta信息,下面接着通过meta信息来进一步获取子类型的MRO链
meta = this.constructor._meta;
bases = meta.bases;
//第一次调用inherited的时候,由于缺少this._inherited信息,
//所以cache是一个空的Object,这里pos是undefined
//但是如果第二回及以后用到了inherited
//那么在cache中记录了之前一次利用inherited寻找的方法和位置
//注意实际上整个实现中并未利用cache,这里的cache疑似某个实现版本遗留下的痕迹
pos = cache.p;
//分情况讨论
//1.要调用的方法不是父类中的构造函数
if(name != cname){
// method
if(cache.c !== caller){
// cache bust
pos = 0;
base = bases[0];
meta = base._meta;
if(meta.hidden[name] !== caller){
// error detection
chains = meta.chains;
if(chains && typeof chains[name] == "string"){
err("calling chained method with inherited: " + name);
}
// find caller
do{
meta = base._meta;
proto = base.prototype;
if(meta && (proto[name] === caller && proto.hasOwnProperty(name) || meta.hidden[name] === caller)){
break;
}
}while(base = bases[++pos]); // intentional assignment
pos = base ? pos : -1;
}
}
// 在正常情况下,在bases[0]中根据name寻找到的方法就是caller
// 因此需要沿着bases继续寻找,有可能会进入while循环,找到的函数放在f中
base = bases[++pos];
if(base){
proto = base.prototype;
if(base._meta && proto.hasOwnProperty(name)){
f = proto[name];
}else{
opf = op[name];
do{
proto = base.prototype;
f = proto[name];
if(f && (base._meta ? proto.hasOwnProperty(name) : f !== opf)){
break;
}
}while(base = bases[++pos]); // intentional assignment
}
}
//这个写法太高级了....就是在bases中没有去就Object.prototype里找
//不过很可能Object.prototype中依然没有名为name的方法,这时候f就是undefined
f = base && f || op[name];
}
//2.要调用的方法是父类中的构造函数
else{
if(cache.c !== caller){
//如果name是constructor,依然是沿着bases依次寻找
pos = 0;
meta = bases[0]._meta;
if(meta && meta.ctor !== caller){
// error detection
chains = meta.chains;
if(!chains || chains.constructor !== "manual"){
err("calling chained constructor with inherited");
}
// find caller
while(base = bases[++pos]){ // intentional assignment
meta = base._meta;
if(meta && meta.ctor === caller){
break;
}
}
pos = base ? pos : -1;
}
}
// 这里找到的父类型的构造函数是base._meta.ctor
// 即当初declare该类型时props中自定义的constructor函数