今天一直在查找类方法之类的题问,上午正好有机会和大家分享一下.
dojo中用应dojo.declare来义定类,它有如下三个数参:
className: 示表类名(即造构函数)的字符串,平日会在全局间空创立这个类,也可以将类名用点割分,如: "myNamespace.Shape",那么Shape就会最为对象myNamespace的性属,如果myNamespace不存在,那么myNamespace.Shapde就会作为全局间空的性属。
superclass: 可选项(null, 函数或者函数数组),指明这个类的父类或者要合聚的类。
props: 一个含包了性属的对象自变量,用来初始化类的原型。如果这个对象自变量中含有一个叫constructor的函数,那么这个函数用来初始化对象实例,叫做初始化函数。
面下用它来创立一个Shape类:
dojo.declare("Shape", null, {color: 0, setColor: function(color) {this.color = color;}});
创立一个Shape对象: var s = new Shpae();
Shape类含包面下性属:
superclass:指向父类原型,如果没有就为undefined。
mixin: 指向合聚类的原型,如果没有就为undefiened。
extend: 一个高等用应,面下要讲。
_constructor: 指向类的初始化函数,这个函数责负造构部全的实例性属,当创立新对象时,有造构函数动自调用。
declaredClass: 就是传给dojo.declare的第一个数参。
inherited: 指向一个于用调用父类方法的函数
用应单继承义定类
为了是子类继承父类,只要将dojo.declare的第二个数参设置为父类的造构函数以可就了:
/*Circle继承自Shape*/ dojo.declare("Circle", Shape, { radius: 0; /*名为constructor的函数来初始化新实例,再调用造构函数的时候被动自调用*/ constructor: function(radius) { this.radius = radius || 0; }, setRadius: function(radius) { this.radius = radius; } });
1 调用父类造构函数
2 调用子类自身的初始化函数
var circle = new Circle(5); /*调用父类造构函数*/ Shape.apply(this, arguments); /*调用子类初始化函数*/ this._constructor.apply(this, arguments);
重载父类的方法
子类平日会覆写父类的方法,而且还会在覆写的方法中调用父类的方法,可以通过inherited方法实现这个作操。
/*Circle继承自Shape*/ dojo.declare("Circle", Shape, { radius: 0; /*名为constructor的函数来初始化新实例,再调用造构函数的时候被动自调用*/ constructor: function(radius) { this.radius = radius || 0; }, setRadius: function(radius) { this.radius = radius; }, /*覆写父类中的setColor方法*/ setColor: function(color) { if (color > 100) { this.inherited(arguments); //调用父类中的本版 } } });
1.function inherited(args, a, func){ 2. // crack arguments 3. if(typeof args == "string"){ 4. name = args; 5. args = a; 6. a = func; 7. } 8. // find method f 9. …… 10. if(f){ 11. return a === true ? f : f.apply(this, a || args); 12. } 13.}
methodName: 要调用的方法名,可选。
args: 即arguments字面量,必选
a: 额定的数参数组,如有这个数参,父类中的方法就不受接arguments字面量。可选
向父类加添方法
向由dojio.declare创立的类的原型中加添方法,该应调用类自带的extend方法,而向其他非dojo.declare创立的造构函数原型中加添方法,调用dojo.extend.
合聚与多继承
dojo.declare可以模拟多继承,这是以合聚的方法实现的。比如在现有一个Circle类,有一个Position类,我们要创立一个新类继承Circle类,合聚Position类:
dojo.declare("CirclePosition", [Circle, Position], { constructor: function(radius, x, y) { this.setPosition(x, y); } });
而当我们实例化一个CirclePosition类时,会执行列下作操:
var circlePosition = new CriclePosition(5, 4, 3); /*父类造构函数被调用*/ Circle.apply(this, arguments); /*父类的造构函数被调用*/ Shape.apply(this, arguments); /*合聚类造构函数被调用*/ Position.apply(this, arguments); /*类本身的初始化函数被调用*/ CirclePosition._constructor.apply(this, arguments);
通过这个对象间空可以发明,CirclePosition的原型对象(6)并没有直接指向Circle的原型对象(7),而是指向了一个旁边造构函数的原型对象(4),这个原型对象才指向了Circle的原型对象,同时,Position原型对象中的性属和方法都被复制到了这个原型对象中(其中基本类型是值复制,而方法以及对象是引用复制,并且是部全的性属,括包Position继承来的)。
从这里还要意注,Position的原型对象不在CirclePosition的原型链中,并且合聚的性属极可能覆盖掉更低级别的原型对象中的同名性属。
预处理造构函数数参
如果类自身,其父类,其合聚的类的造构函数的数参签名不一样,那么,在初始化一个类实例的时候极可能出题问。如:CirclePosition继承自Circle类,Circle类继承自Shape类,同时CriclePosition类合聚Position类。其中CirclePosition的造构函数签名(radius, x, y), Circle造构函数的签名(radius), Shape造构函数的签名(), Position造构函数的签名(x, y)。那么当实例化一个CirclePosition时:
var circlePosition = new CirclePosition(5, 4, 3); /*面下的函数调用将顺次执行*/ Circle.apply(this, [5, 4, 3]); Shape.apply(this, [5, 4, 3]); Position.apply(this, [5, 4, 3]); CirclePosition.prototype._constructor.apply(this, [5, 4, 3]);
function constructor(raduis, x, y) { this.setPosition(x, y);//setPosition是Position类中的方法,用来设置x, y的值 }
1 受接预处理器
dojo.declare受接一个预处理器(即一个函数),这个预处理器义定在传递给它的但三个数参里头,这个预处理器被义定为一个叫preamble的性属。这个预处理器会在数参传递个父类或者合聚类的造构函数时,先对数参停止格式化,以生产合适父类或者造构函数的数参。事先单继承或者没有合聚类,或者合聚类和父类的数参都一样的时候,这中方法可以作工的很好。但是当合聚类和父类的造构函数数参不一致的时候,就会出题问,因为这个预处理器格式化的数参要么只合适父类,要么只合适合聚类。为了处理这个题问,我们可以创立一个夹层类(Shim Class),以上面的CriclePosition为例,首先创立一个夹层类,它集成自Position类:
dojo.declare("PositionShimClass", Position, { preamble: funciton(raduis, x, y) { //预处理器 return [x || null, y || null]; } }
然后用这个PositionShimClass来合聚CirclePosition:
dojo.declare("CirclePosition", [Circle, PositionShimClass], {});
var circlePosition = new CirclePosition(5, 4, 3); /*面下的函数调用将顺次执行*/ Circle.apply(this, [5, 4, 3]); Shape.apply(this, [5, 4, 3]); PositionShimClass.apply(this, PositionShimClass.prototype.preamble.apply(this, [5, 4, 3]); //预处理后的数参将传递给Position造构函数 if (CirclePosition.prototype._constructor) {//如果初始化函数存在 CirclePosition.prototype._constructor.apply(this, [5, 4, 3]); }
2 用对象字面量来传递数参
var circlePosition = new CirclePosition({ radius: 5, x: 4, y: 3 }); /*Circle类中的初始化函数*/ function constructor(args) { if (args && args.radius) { this.radius = args.radius; } } /*Position类中的初始化函数*/ function constructor(args) { if (args && args.x && args.y) { this.x = args.x; this.y = args.y; } }
处理名字冲突:
合聚类中的部全性属被加添到了新类的原型链中,而这些性属在原型链中的位置位于父类之上,因此当涌现同名性属时,极可能会覆盖掉父类中的性属。我们仍以CirclePosition,Circle, Shape, Position为例。CirclePosition继承自Cricle, Circle继承自Shape,同时CriclePosition合聚Position。Circle中有setRadius方法,Shape中有setColor方法,Position中有setPosition方法。如果以这类方法名命,他们不会生产冲突,但是如果他们都名命为set,那么就会生产冲突。当CirclePosition的实例调用set方法时,只有Position中的set方法被调用。处理这类题问的方法是给Position的set方法重名命:
CirclePosition.extend({ setPosition: Position.prototype.set }); delete CirclePosition.superclass.set;
两阶段造构
假设有这样的一个几类Base:
dojo.declare("Base", null, { constructor: function() { this.args = {baseArags: dosomething(this); } }
这个基类中的初始化函数要求实例全完造构实现以后调用才行,如果从这个基类生派出一个子类subclass,由于父类的初始化函数在子类初始化函数实现之前被调用,因此这个父类初始化函数将不能畸形作工。因此我们要需证保子类经已被全完造构,再来调用这个方法,而dojo.declare的第三个对象字面量数参供给postscript性属来实现这个作操。它证保这个性属义定的方法会在部全方法被调用以后(括包父类造构器方法,合聚类造构器方法,子类自身的初始化方法),这个方法才在新实例上执行。这就是两阶段造构。
用应postscript必须意注,它仅仅被终最生派出来的类调用,如果父类义定了这个方法,而子类没有义定,那么调用的就是父类的方法;如果子类覆写了这个方法,那么可以通过this.inherited(arguments)实现,并且这个方法受接的数参是传递给造构器的数参。
面下我们来看一个例子,父类和子类将会把它们受接的字符存到args变量中,然后再将他们部全输出来。首先不实用postscript:
/*父类*/ dojo.declare("Base", null, { constructor: function() { this.args = {baseArgs: dojo._toArray(arguments)}; console.log(dojo.toJson(this.args, true)); }); /*子类*/ dojo.declare("Subclass", Base, { constructor: function() { this.args.subArags = dojo._toArray(arguments); }, preamble: function() { return dojo._toArray(arguments).slice(0, 3); //父类只得到其中的三个数参 } }); var subClass = new Subclass(1, 2, 3, 4, 5, 6);
在现修改如下:
ojo.declare("Base", null, { constructor: function() { this.args = {baseArgs: dojo._toArray(arguments)}; }, postscript: function() { console.log(dojo.toJson(this.args, true)); } ); dojo.declare("Subclass", Base, { constructor: function() { this.args.subArgs = dojo._toArray(arguments); }, postscript: function() { console.log("in subclass"); this.inherited(arguments); }, preamble: function() { return dojo._toArray(arguments).slice(0, 3); } });
不实用造构函数生产自义定对象:
dojo.delegate(obj, propt): 创立并返回一个新对象,并利用dojo.mixin将propt合并到新对象中:
var Base = { greet: function() { return "Hello, my Name is " + this.name; } }; var newObject = dojo.delegate(Base, {name: "Jone"});
文章结束给大家分享下程序员的一些笑话语录: 一程序员告老还乡,想安度晚年,于是决定在书法上有所造诣。省略数字……,准备好文房4宝,挥起毛笔在白纸上郑重的写下:Hello World