JavaScript 中的抽象类和虚拟方法
一:抽象类与虚方法
虚方法是类成员中的概念,是只做了一个声明而未实现的方法,具有虚方法的类就称之为抽象类,这些虚方法在派生类中才被实现。抽象类是不能实例化的,因为其中的虚方法并不是一个完整的函数,不能被调用。所以抽象类一般只作为基类被派生以后再使用。 和类的继承一样,JavaScript并没有任何机制用于支持抽象类。但利用JavaScript语言本身的性质,可以实现自己的抽象类。
二: 在JavaScript实现抽象类
在传统面向对象语言中,抽象类中的虚方法必须先被声明,但可以在其他方法中被调用。而在JavaScript中,虚方法就可以看作该类中没有定义的方法,但已经通过this指针使用了。和传统面向对象不同的是,这里虚方法不需经过声明,而直接使用了。这些方法将在派生类中实现,例如:
<script language="JavaScript" type="text/javascript">
<!--
//定义extend方法
Object.extend = function(destination, source) {
for (property in source) {
destination[property] = source[property];
}
return destination;
}
Object.prototype.extend = function(object) {
return Object.extend.apply(this, [this, object]);
}
//定义一个抽象基类base,无构造函数
function base(){}
base.prototype={
initialize:function(){
this.oninit(); //调用了一个虚方法
}
}
//定义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(){
this.oninit(); //调用了一个虚方法
},
oninit:function(){} //虚方法是一个空方法,由派生类实现
}
实例
仍然以prototype-1.6.1为例,其中定义了一个类的创建模型:
//Class是一个全局对象,有一个方法create,用于返回一个类
var Class = {
create: function() {
return function() {
this.initialize.apply(this, arguments);
}
}
}
这里Class是一个全局对象,具有一个方法create,用于返回一个函数(类),从而声明一个类,可以用如下语法:
var class1=Class.create();
这样和函数的定义方式区分开来,使JavaScript语言能够更具备面向对象语言的特点。现在来看这个返回的函数(类):
function(){
this.initialize.apply(this, arguments);
}
这个函数也是一个类的构造函数,当new这个类时便会得到执行。它调用了一个initialize方法,从名字来看,是类的构造函数。而从类的角度来看,它是一个虚方法,是未定义的。但这个虚方法的实现并不是在派生类中实现的,而是创建完一个类后,在prototype中定义的,例如prototype可以这样写:
var class1=Class.create();
class1.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中不是一个抽象类的概念,而是类的一种设计模式。但实际上可以把Class.create()返回的类看作所有类的共同基类,它在构造函数中调用了一个虚方法initialize,所有继承于它的类都必须实现这个方法,完成构造函数的功能。它们得以实现的本质就是对prototype的操作。
具体代码:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/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 = Class.create();
Person.prototype={
//必须给初始化值
initialize: function(name) {
this.personName=name;
},
showInfo:function(){
alert(this.personName);
}
}
子类的js:
/**
* Created by shizhiwei on 2016/9/11.
*/
var Employee = Class.create();
Employee.prototype = Object.extend(new Person(), {
//定义一个抽象类
initialize: function(name,corp) {
this.personName=name;
this.corpName=corp;
},
// corpName:"Micosoft",
showInfo:function(){
return this.personName+","+this.corpName;
}
});
转载于:https://www.cnblogs.com/sunliyuan/p/5862921.html
上一篇: 数字与字符对照表(编码表)
下一篇: Javascript 中的钩子技术
推荐阅读
-
C++ 中的抽象类和抽象方法
-
力扣 1884.Egg Drop Two Egg(两个鸡蛋掉落) - 输入: n = 100 输出: 1414 解说 最佳策略是 - 从 9 楼扔下第一个鸡蛋。如果蛋碎了,那么 f 在 0 和 8 之间。从第 1 层扔第 2 个鸡蛋,然后每扔 1 层,分 8 次找到 f。总操作次数 = 1 + 8 = 9。 - 如果第一个鸡蛋没有破,那么从 22 楼扔第一个鸡蛋。如果蛋碎了,那么 f 介于 9 和 21 之间。将第二个鸡蛋从 10 楼往下扔,然后每扔一次往上扔一层楼,在 12 次尝试中找出 f。总操作次数 = 2 + 12 = 14。 - 如果第一个鸡蛋没有再次破碎,那么用类似的方法从 34、45、55、64、72、79、85、90、94、97、99 和 100 层扔第一个鸡蛋。 无论结果如何,最多需要扔 14 次才能确定 f。 一个非常有趣的问题 方法 1:动态编程
-
解释 JavaScript 中函数的实参和形参
-
Java 8新特性探究(十三)JavaFX 8新特性以及开发2048游戏-JavaFX历史## 跟java在服务器端和web端成绩相比,桌面一直是java的软肋,于是Sun公司在2008年推出JavaFX,弥补桌面软件的缺陷,请看下图JavaFX一路走过来的改进 从上图看出,一开始推出时候,开发者需使用一种名为JavaFX Script的静态的、声明式的编程语言来开发JavaFX应用程序。因为JavaFX Script将会被编译为Java bytecode,程序员可以使用Java代码代替。 JavaFX 2.0之后的版本摒弃了JavaFX Script语言,而作为一个Java API来使用。因此使用JavaFX平台实现的应用程序将直接通过标准Java代码来实现。 JavaFX 2.0 包含非常丰富的 UI 控件、图形和多媒体特性用于简化可视化应用的开发,WebView可直接在应用中嵌入网页;另外 2.0 版本允许使用 FXML 进行 UI 定义,这是一个脚本化基于 XML 的标识语言。 从JDK 7u6开始,JavaFx就与JDK捆绑在一起了,JavaFX团队称,下一个版本将是8.0,目前所有的工作都已经围绕8.0库进行。这是因为JavaFX将捆绑在Java 8中,因此该团队决定跳过几个版本号,迎头赶上Java 8。 ##JavaFx8的新特性 ## ###全新现代主题:Modena 新的Modena主题来替换原来的Caspian主题。不过在Application的start方法中,可以通过setUserAgentStylesheet(STYLESHEET_CASPIAN)来继续使用Caspian主题。 参考http://fxexperience.com/2013/03/modena-theme-update/ ###JavaFX 3D 在JavaFX8中提供了3D图像处理API,包括Shape3D (Box, Cylinder, MeshView, Sphere子类),SubScene, Material, PickResult, LightBase (AmbientLight 和PointLight子类),SceneAntialiasing等。Camera类也得到了更新。从JavaDoc中可以找到更多信息。 ###富文本 强化了富文本的支持 ###TreeTableView ###日期控件DatePicker 增加日期控件 ###用于 CSS 结构的公共 API
-
远程访问和虚拟化串口在Linux系统中的应用
-
解析Python中的类的方法和概念
-
通过增强版RFM模型,揭示B站优秀up主的简单方法!(包含数据和实战代码)(中)
-
堆排序中 Go 语言中使用大顶堆和小顶堆的方法
-
在js中实现大顶堆和小顶堆的操作(javascript)
-
配置HP FC存储设备多路径驱动的方法在linux和Windows操作系统中即可实现