js 设计模式 第四章

来源:互联网 发布:淘宝漏洞券怎么找 编辑:程序博客网 时间:2024/04/29 11:58

继承


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 适合增强类,两个类在语义世界里,没有继承关系