JavaScript实现抽象类与虚⽅法(六)
⼀:什么是js抽象类与虚⽅法
虚函数是类成员中的概念,是只做了⼀个声明⽽未实现的⽅法,具有虚函数的类就称之为抽象类,这些虚函数在派⽣类中才被实现。抽象类是不能实例化的,因为其中的虚函数并不是⼀个完整的函数,不能被调⽤。所以抽象类⼀般只作为基类被派⽣以后再使⽤。
和类的继承⼀样,JavaScript并没有任何机制⽤于⽀持抽象类。但利⽤JavaScript语⾔本⾝的性质,可以实现⾃⼰的抽象类。
⼆:在JavaScript实现抽象类
在传统⾯向对象语⾔中,抽象类中的虚⽅法必须先被声明,但可以在其他⽅法中被调⽤。⽽在JavaScript中,虚⽅法就可以看作该类中没有定义的⽅法,但已经通过this指针使⽤了。和传统⾯向对象不同的是,这⾥虚⽅法不需经过声明,⽽直接使⽤了。这些⽅法将在派⽣类中实现,例如:
<script language="JavaScript" type="text/javascript">
<!--
//定义extend⽅法
for (property in source) {
destination[property] = source[property];
}
return destination;
}
d = function(object) {
d.apply(this, [this, object]);
}
//定义⼀个抽象基类base,⽆构造函数
function base(){}
base.prototype={
initialize:function(){
}
}
//定义class1
function class1(){
//构造函数
}
//让class1继承于base并实现其中的oninit⽅法
class1.prototype=(new base()).extend({
oninit:function(){ //实现抽象基类中的oninit虚⽅法
//oninit函数的实现
}
});
//-->
</script>
这样,当在class1的实例中调⽤继承得到的initialize⽅法时,就会⾃动执⾏派⽣类中的oninit()⽅法。从这⾥也可以看到解释型语⾔执⾏的特点,它们只有在运⾏到某⼀个⽅法调⽤时,才会检查该⽅法是否存在,⽽不会向编译型语⾔⼀样在编译阶段就检查⽅法存在与否。JavaScript中则避免了这个问题。当然,如果希望在基类中添加虚⽅法的⼀个定义,也是可以的,只要在派⽣类中覆盖此⽅法即可。例如://定义⼀个抽象基类base,⽆构造函数
function base(){}
base.prototype={
initialize:function(){
},
oninit:function(){} //虚⽅法是⼀个空⽅法,由派⽣类实现
}
代码:
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8"/>
<script type="text/javascript" src="js/Core.js"></script>
<script type="text/javascript">
function Base(){
}
Base.prototype={
initialize:function(){
},
oninit:function(){
//留⼀个空的⽅法
}
}
function Class01(){
}
Class01.prototype=(new Base()).extend({
oninit:function(){ //实现抽象基类中的oninit虚⽅法
//oninit函数的实现
console.log("");
}
});
var class01 = new Class01();
class01.initialize();
</script>
</head>
<body>
</body>
</html>
三:使⽤抽象类的⽰例
仍然以prototype-1.6.1为例,其中定义了⼀个类的创建模型:
//Class是⼀个全局对象,有⼀个⽅法create,⽤于返回⼀个类
var Class = {
create: function() {
return function() {
this.initialize.apply(this, arguments);
}
}
}
这⾥Class是⼀个全局对象,具有⼀个⽅法create,⽤于返回⼀个函数(类),从⽽声明⼀个类,可以⽤如下语法:
var ate();
这样和函数的定义⽅式区分开来,使JavaScript语⾔能够更具备⾯向对象语⾔的特点。现在来看这个返回的函数(类):
function(){
this.initialize.apply(this, arguments);
}
这个函数也是⼀个类的构造函数,当new这个类时便会得到执⾏。它调⽤了⼀个initialize⽅法,从名字来看,是类的构造函数。⽽从类的⾓度来看,它是⼀个虚⽅法,是未定义的。但这个虚⽅法的实现并不是在派⽣类中实现的,⽽是创建完⼀个类后,在prototype中定义的,例如prototype可以这样写:
var ate();
js argumentsclass1.prototype={
initialize:function(userName){
alert(“hello,”+userName);
}
}
这样,每次创建类的实例时,initialize⽅法都会得到执⾏,从⽽实现了将类的构造函数和类成员⼀起定义的功能。其中,为了能够给构造函数传递参数,使⽤了这样的语句:
function(){
this.initialize.apply(this, arguments);
}
实际上,这⾥的arguments是function()中所传进来的参数,也就是new class1(args)中传递进来的args,现在要把args传递给initialize,巧妙的使⽤了函数的apply⽅法,注意不能写成:
this.initialize(arguments);
这是将arguments数组作为⼀个参数传递给initialize⽅法,⽽apply⽅法则可以把arguments数组对象的元素作为⼀组参数传递过去,这是⼀种很巧妙的实现。
尽管这个例⼦在prototype-1.3.1中不是⼀个抽象类的概念,⽽是类的⼀种设计模式。但实际上可以把ate()返回的类看作所有类的共同基类,它在构造函数中调⽤了⼀个虚⽅法initialize,所有继承于它的类都必须实现这个⽅法,完成构造函数的功能。它们得以实现的本质就是对prototype的操作。
具体代码:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"/TR/html4/loose.dtd">
<html>
<head>
<title></title>
<script type="text/javascript" src="js/prototype-1.6.0.3.js"></script> <script type="text/javascript" src="js/Person.js"></script>
<script type="text/javascript" src="js/Employee.js"></script>
<script type="text/javascript">
//创建⼀个类
function getEmployeeInfo(){
var employee = new Employee("sunliyuan","Miscofo");
var info = employee.showInfo();
alert(info);
}
</script>
</head>
<body>
<button onclick="getEmployeeInfo()">GetEmployeeInfo</button>
</body>
</html>
⽗类js:
/**
* Created by shizhiwei on 2016/9/11.
*/
var Person = ate();
Person.prototype={
//必须给初始化值
initialize: function(name) {
this.personName=name;
},
showInfo:function(){
alert(this.personName);
}
}
⼦类的js:
/**
* Created by shizhiwei on 2016/9/11.
*/
var Employee = ate();
Employee.prototype = d(new Person(), {
//定义⼀个抽象类
initialize: function(name,corp) {
this.personName=name;
},
// corpName:"Micosoft",
showInfo:function(){
return this.personName+","+pName;
}
});
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论