理解YUI3 extension:Base.create

YUI3中为了避免不必要的类继承层次,以及摆脱利用原型链模拟的单继承模型,除了利用Y.augment 来扩充单一类功能的机制,对用多功能扩充更提出了扩展类的概念(另一个和augment的不同点在于扩充功能类的构造函数调用时机),能够方便的将功能分解,对应 Base.create。


利用官方例子解释:

 

比如某个类继承了Widget但是它想有Stack,Position的功能,那么按照传统设计就要该做继承WidgeStackPosition,而WidgeStackPosition再继承Widget,这两个功能实际上绑定在一起了,而对于使用者这种深层的类链是不必要的,使用者只需知道这是个Widget,它有stack,position的功能即可。于是yui3有了Base.create功能:

 

var Positionable = Y.Base.create("positionable", Y.Widget, 
	                            [Y.WidgetStack,Y.WidgetPosition]);

 

动态生成了一个类,这个类是Widget的子类,但并不是WidgetStack或WidgePositon的子类,并且这两个功能互相独立,WidgetStack,Position也很简单只是一个单纯类,描述了功能,其并没有继承Widget,这样就完成了是Widget的子类但具有Stack,Positon功能这一需求,避免了继承的滥用以及功能的灵活配置。


原理:

 

简单的说:利用了脚本语言的动态特性,将extension class的prototype混合在新生成类的prototype中,使新生成类具有了扩展类的特有功能。


但是这样的话,就丧失了传统类继承时yui3 oop的一些特性,比如Stack可以利用静态 ATTRS 来设置自己的属性,更关键的是只赋值功能代码的话,Stack的构造初始化函数没有机会运行,而构造函数中也许存在他的功能函数所依赖的状态。


具体的说:create干了很多事,并且需要Base的配合,这也就是为什么create要求的基类一定要继承自Base:


1。不仅要复制extension class的prototype功能函数到新生成类,还要复制extension class的静态属性到新生成类。


2。在初始化新生成类的实例时,要调用extension class的构造函数,这点正是 Base 基类初始化所考虑的,所以新生成类一定要以Base为基类,那么在初始化新生成类实例时,调用Base的初始构造函数,这时再调用新生成类所有 extension class 的构造函数,于是执行了扩展类的初始化:

 

//Base._initHierarchy :
//......
for (ci = classes.length - 1; ci >= 0; ci--) {
    constr = classes[ci];
    constrProto = constr.prototype;
    //初始化继承链上对应类的扩展类
    if (constr._yuibuild && constr._yuibuild.exts) {
        for (ei = 0, el = constr._yuibuild.exts.length; ei < el; ei++) {
            constr._yuibuild.exts[ei].apply(this, arguments);
        }
    }
//.....
}

 


换个实现看:


根据以上的分析,对应于:

 

var Positionable = Y.Base.create("positionable", Y.Widget, 
	                            [Y.WidgetStack,Y.WidgetPosition]);

 

也即简化为这样的实现,加深理解:

 

function Positionable() {
    Positionable.superclass.constructor.apply(this, arguments);
}
Positionable._yuibuild = Positionable._yuibuild || {};
Positionable._yuibuild.exts = Positionable._yuibuild.exts || [];
//Base调用初始化
Positionable._yuibuild.exts.push(Y.WidgetStack);
Positionable._yuibuild.exts.push(Y.WidgetPosition);
Positionable.NAME = "positionable";
Y.extend(Positionable, Y.Widget);
//属性
Y.mix(Positionable, Y.WidgetStack);
//功能代码prototype
Y.mix(Positionable.prototype, Y.WidgetStack.prototype);
Y.mix(Positionable, Y.WidgetPosition);
Y.mix(Positionable.prototype, Y.WidgetPosition.prototype)
 

你可能感兴趣的:(prototype,脚本,oop)