类方法定义类

今天一直在查找类方法之类的题问,上午正好有机会和大家分享一下.

    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;
    }
});
当创立一个Circle对象时,dojo会做两件事:

    1 调用父类造构函数

    2 调用子类自身的初始化函数

var circle = new Circle(5);

/*调用父类造构函数*/
Shape.apply(this, arguments);
/*调用子类初始化函数*/
this._constructor.apply(this, arguments);
Circle类的原型会指向Shape的原型。

    重载父类的方法

    子类平日会覆写父类的方法,而且还会在覆写的方法中调用父类的方法,可以通过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); //调用父类中的本版
        }
    }
});
inherited会找到父类中的方法,然后通过面下的情势调用:
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.}  
i nherited受接三个数参:

    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);
    }
});
这里,dojo.declare的第二个数参为一个造构函数数组,其中的第一个造构函数会被继承,面后的造构函数会被合聚。

    而当我们实例化一个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对象间空

    类和方法

 

    通过这个对象间空可以发明,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]);
    每日一道理
风,那么轻柔,带动着小树、小草一起翩翩起舞,当一阵清风飘来,如同母亲的手轻轻抚摸自己的脸庞,我喜欢那种感觉,带有丝丝凉意,让人心旷神怡。享受生活,不一定要有山珍海味、菱罗绸缎为伴,大自然便是上帝所赐予人类最为珍贵的。
由于Circle只受接radius数参,因此够能被畸形初始化,Shape类不受接任何数参,因此也够能畸形初始化,而Position受接x,y作数参,因此,它会将radius当做x,把x当做y,不够能畸形初始化。但是我们可以将Circle的初始化函数义定成:
function constructor(raduis, x, y) {
    this.setPosition(x, y);//setPosition是Position类中的方法,用来设置x, y的值
}
这样,尽管Position造构函数初始化不确正,但是CirclePosition的初始化函数还是可以确正初始化。用应这类方法大多数况情下不会涌现题问,但有时候也会跑出异常。有两种方法可以处理这个题问:

    1 受接预处理器

    dojo.declare受接一个预处理器(即一个函数),这个预处理器义定在传递给它的但三个数参里头,这个预处理器被义定为一个叫preamble的性属。这个预处理器会在数参传递个父类或者合聚类的造构函数时,先对数参停止格式化,以生产合适父类或者造构函数的数参。事先单继承或者没有合聚类,或者合聚类和父类的数参都一样的时候,这中方法可以作工的很好。但是当合聚类和父类的造构函数数参不一致的时候,就会出题问,因为这个预处理器格式化的数参要么只合适父类,要么只合适合聚类。为了处理这个题问,我们可以创立一个夹层类(Shim Class),以上面的CriclePosition为例,首先创立一个夹层类,它集成自Position类:

 

dojo.declare("PositionShimClass", Position,  {
    preamble: funciton(raduis, x, y) { //预处理器
        return [x || null, y || null];
    }
}
里头的预处理器将为Position格式化数参。

    然后用这个PositionShimClass来合聚CirclePosition:

dojo.declare("CirclePosition", [Circle, PositionShimClass], {});
当此时在创立CirclePosition的实例时:
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;
那么接下来如何清除Cricle.set和Shape.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"});
当调用newObject.greet()时生产"Hello, my name is Jone".

文章结束给大家分享下程序员的一些笑话语录: 一程序员告老还乡,想安度晚年,于是决定在书法上有所造诣。省略数字……,准备好文房4宝,挥起毛笔在白纸上郑重的写下:Hello World


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值