首页 » 编写高质量代码:改善JavaScript程序的188个建议 » 编写高质量代码:改善JavaScript程序的188个建议全文在线阅读

《编写高质量代码:改善JavaScript程序的188个建议》建议94:建议使用封装类继承

关灯直达底部

在面向对象编程中,语言自身都有一套严格的封装机制,开发人员只是按惯性思维去开发具体的项目,很少关心封装问题,因为语言会自动完成基本的功能封装,当然具体应用的功能还需要程序人员自己去封装。但是,JavaScript语言没有提供良好的封装机制,只能够依靠开发人员的方法来实现部分功能封装。类继承是在JavaScript程序开发中应用得比较广泛的继承模式,为了更方便地使用,建议读者对这种模式进行规范和封装,以便提高代码利用率。

首先,定义一个封装函数。设计入口为子类和超类对象,函数功能是子类能够继承超类的所有原型成员,不设计出口:


function extend(Sub,Sup){//类继承封装函数

//参数Sub表示子类,Sup表示超类

}


在函数体内,首先定义一个空函数F,用来实现功能中转。设计F的原型为超类的原型,然后把空函数的实例传递给子类的原型,这样就避免了直接实例化超类可能带来的系统负荷。在实际开发中,超类的规模可能会很大,进行实例化会占用大量内存。

恢复子类原型的构造器子类,同时,检测超类的原型构造器是否与Object的原型构造器发生耦合,如果是,则恢复它的构造器为超类自身。


function extend(Sub,Sup){//类继承封装函数

var F=function{};//定义一个空函数

F.prototype=Sup.prototype;//设置空函数的原型为超类的原型

Sub.prototype=new F;//实例化空函数,并把超类原型引用传递给子类

Sub.prototype.constructor=Sub;//恢复子类原型的构造器为子类自身

Sub.sup=Sup.prototype;//在子类中存储超类原型,避免子类和超类耦合

if(Sup.prototype.constructor==Object.prototype.constructor){//检测超类原型构造器是否为自身

Sup.prototype.constructor=Sup//类继承封装函数

}

}


一个简单的功能封装函数就这样实现了。下面定义两个类,尝试把它们绑定为继承关系。


function A(x){//构造函数A

this.x=x;

this.get=function{

return this.x;

}

}

A.prototype.add=function{

return this.x+this.x;

}

A.prototype.mul=function{

return this.x*this.x;

}

function B(x){//构造函数B

A.call(this,x);//在函数体内调用构造函数A,实现内部数据绑定

}

extend(B,A);//调用类继承封装函数,把A和B的原型捆绑在一起

var f=new B(5);

alert(f.get)//5

alert(f.add)//10

alert(f.mul)//25


在类继承封装函数中,有这样的语句“Sub.sup=Sup.prototype;”,在上面的代码中没有体现,为了理解它的价值,先看下面的代码:


extend(B,A);

B.prototype.add=function{//为B类定义一个原型方法

return this.x+""+this.x

}


上面的代码是在调用封装函数之后再为B类定义了一个原型方法,该方法名与A类的原型方法add同名,但功能不同。如果此时测试程序,那么会发现子类B定义的原型方法add将会覆盖超类A的原型方法add,如下:


alert(f.add)//字符串55,而不是数值10


在B类的原型方法add中调用超类的原型方法add,从而避免代码耦合的现象发生:


B.prototype.add=function{

return B.sup.add.call(this);//在函数内部调用超类的方法add

}