您的位置:首页 > Web前端 > JavaScript

js 设计模式 第四章

2012-10-17 09:02 323 查看
继承

why?

多个类公用的功能,如果重复拷贝,一方面,工作量大,另一方面,如果公用功能需要修改,则需要修改所有类中的这个功能,重复工作量大。

为了减少复制以及带来的不利于修改的问题,我们需要继承

how?

三种方法:Classical Inheritance Prototypal Inheritance Mixin Classes

what?

第一种方法:Classical Inheritance

function Animal(type){
    this.type = type;
}
Animal.prototype.getType = function(){
    return this.type;
}


利用原型链,实现继承

function Pat(type,name){
    Animal.call(this,type);
    this.name = name;
}
Pat.prototype = new Animal();
Pat.prototype.constructor = Pat;
Pat.prototype.getName = function(){
    return this.name;
}


这种方法的实现步骤是:

1 在构造函数中,调用父类的构造函数,通过apply或者call方法,将父类的执行环境变成子类的执行环境。这可以让子类有父类的public 属性

2 建立原型链。在js中,所有对象都有一个prototype的属性,这个属性指向别的对象或者null。当访问对象的一个属性时,寻找的路径方式是:先在对象内寻找,如果不存在,则到这个对象的prototype指向的对象中找,还是没有找到,则到prototype指向对象的prototype指向对象中继续寻找,知道找到属性或者prototype为null。利用js的这个特性,要让子类继承父类,只需要让子类的prototype 指向父类的一个实例。

3 将子类的prototype对象的constructor属性赋值为子类对象名。因为当你将子类的prototype属性赋值为父类的一个实例时,子类的prototype被清空了。

为了简化继承的过程,我们通过函数,封装上面的流程

function extend(subClass,superClass){
    var F = function(){};    //1
    F.prototype = superClass.prototype;
    subClass.prototype = new F();
    subClass.prototype.constructor = subClass;

//让子类有一个类属性,指向父类
    subClass.superclass = superClass.prototype;
    if(superClass.prototype.constructor == Object.prototype.constructor){//2
        superClass.prototype.constructor = superClass;
    }

}
利用extend 继承的方法如下:

function Pat(type,name){
    Pat.superclass.constructor.call(this,type);//3
    this.name = name;
}
extend(Pat,Animal);
Pat.prototype.getName = function(){
    return this.name;
}


在extend 方法中,有两个地方需要再解释下:

1 在继承中,为了获得父类的原型链,我们让子类的prototype指向了父类的一个实例对象,而父类实例化对象的属性并不是我们需要的,如果父类构造函数比较负责,这样就照成了不小的浪费。在extend 中,我们通过一个空的类,让空类的prototype指向了父类的原型链,进而让子类的原型链执行空类的对象,达到了目的。

2 如果父类的prototype被重置,而没有重新给constructor 赋值,constructor 属性将指向Object,故通过判断,如果没有赋值,则重新给他赋值。这样,就能保证在注释3的位置中,superclass.constructor ,指向了正确的类。

第一种方法:Prototypal Inheritance

fuction clone(object){
    function F(){}
    F.prototype = object;
    return new F;
}


var Animal = {
    type : "dog",
    getType:function(){
        return this.type;
    }
}
var Pat = clone(Animal);
Pat.name ="xiaoge";
Pat.getName = function(){
     return this.name;
}
var cat = clone(Pat);
cat.name="mimi";
alert(cat.getName);//mimi


这种方法,通过常量对象来模拟继承。这种方法的好处,是所有子类默认公用父类的属性和方法,是一种节约内存的有效方法。而经典的继承方式中,所有子类对象都保存了一份属性。

第三种方法:Mixin Classes

通过将公用类的prototype中的方法,拷贝到类中,实现对类能力的增强

关键的函数

var Mixin = function(){};
Mixin.portotype = {
    serialize:function(){
        var output = [];
        for(key in this){
            output.push(key+':' + this[key]);
        return output.join(',');
        }
    }
};
function augment(receivingClass,givingClass){
    for(methodName in givingClass.prototype){
        if(!receivingClass.prototype[methodName){
            receivingClass.prototype[methodName] = givingClass.prototype[methodName];
        }
}
}


Mixin 中通过prototype 包含公用的函数

augment 中,将Mixin中的函数都拷贝到receivingClass中,除非receivingClass中已定义该方法。

几种方法的比较:

classical inheritance 简单易懂,最接近其他语言继承的流程

prototypal inheritance 适用与内存比较紧张的情况

mixin Classes 适合增强类,两个类在语义世界里,没有继承关系
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: