用JavaScript实现抽象类

本文阅读 6 分钟
首页 知识库 正文

了解抽象类的实现,有利于积累创造自己的JavaScript框架/库的能力。在ECMAScript 6之前,和类的继承一样,JavaScript并没有任何机制用于支持抽象类;但利用JavaScript语言本身的性质,可以实现自己的抽象类。

01.抽象类与虚方法

  • 虚方法是类成员中的概念,是只做了一个声明而未实现的方法。
  • 具有虚方法的类就称之为抽象类。
  • 这些虚方法在派生类中才被实现。
  • 抽象类是不能实例化的,因为其中的虚方法并不是一个完整的函数,不能被调用。所以抽象类一般只作为基类被派生以后再使用。

02.实现抽象类

在传统面向对象语言中,抽象类中的虚方法必须先被声明,但可以在其他方法中被调用。而在JavaScript中,虚方法就可以看作该类中没有定义的方法,但已经通过this指针使用了。和传统面向对象不同的是,这里虚方法不需经过声明,而直接使用了。这些方法将在派生类中实现,例如:

  1. //定义extend方法
  2. Object.extend = function(destination, source) {
  3. for (property in source) {
  4. destination[property] = source[property];
  5. }
  6. return destination;
  7. }
  8. Object.prototype.extend = function(object) {
  9. return Object.extend.apply(this, [this, object]);
  10. }
  11. //定义一个抽象基类base,无构造函数
  12. function base(){}
  13. base.prototype={
  14. initialize:function(){
  15. this.oninit(); //调用了一个虚方法
  16. }
  17. }
  18. //定义class1
  19. function class1(){
  20. //构造函数
  21. }
  22. //让class1继承于base并实现其中的oninit方法
  23. class1.prototype=(new base()).extend({
  24. oninit:function(){ //实现抽象基类中的oninit虚方法
  25. //oninit函数的实现
  26. }
  27. });

这样,当在class1的实例中调用继承得到的initialize方法时,就会自动执行派生类中的oninit()方法。从这里也可以看到解释型语言执行的特点,它们只有在运行到某一个方法调用时,才会检查该方法是否存在,而不会向编译型语言一样在编译阶段就检查方法存在与否。JavaScript中则避免了这个问题。当然,如果希望在基类中添加虚方法的一个定义,也是可以的,只要在派生类中覆盖此方法即可。例如:

  1. //定义一个抽象基类base,无构造函数
  2. function base(){}
  3. base.prototype={
  4. initialize:function(){
  5. this.oninit(); //调用了一个虚方法
  6. },
  7. oninit:function(){} //虚方法是一个空方法,由派生类实现
  8. }

03.示例

仍然以prototype-1.6.1为例,其中定义了一个类的创建模型:

  1. //Class是一个全局对象,有一个方法create,用于返回一个类
  2. var Class = {
  3. create: function() {
  4. return function() {
  5. this.initialize.apply(this, arguments);
  6. }
  7. }
  8. }

这里Class是一个全局对象,具有一个方法create,用于返回一个函数(类),从而声明一个类,可以用如下语法:

  1. var class1=Class.create();

这样和函数的定义方式区分开来,使JavaScript语言能够更具备面向对象语言的特点。现在来看这个返回的函数(类):

  1. function(){
  2. this.initialize.apply(this, arguments);
  3. }

这个函数也是一个类的构造函数,当new这个类时便会得到执行。它调用了一个initialize方法,从名字来看,是类的构造函数。而从类的角度来看,它是一个虚方法,是未定义的。但这个虚方法的实现并不是在派生类中实现的,而是创建完一个类后,在prototype中定义的,例如prototype可以这样写:

  1. var class1=Class.create();
  2. class1.prototype={
  3. initialize:function(userName){
  4. alert(“hello,”+userName);
  5. }
  6. }

这样,每次创建类的实例时,initialize方法都会得到执行,从而实现了将类的构造函数和类成员一起定义的功能。其中,为了能够给构造函数传递参数,使用了这样的语句:

  1. function(){
  2. this.initialize.apply(this, arguments);
  3. }

实际上,这里的arguments是function()中所传进来的参数,也就是new class1(args)中传递进来的args,现在要把args传递给initialize,巧妙的使用了函数的apply方法,注意不能写成:

  1. this.initialize(arguments);

这是将arguments数组作为一个参数传递给initialize方法,而apply方法则可以把arguments数组对象的元素作为一组参数传递过去,这是一种很巧妙的实现。 尽管这个例子在prototype-1.3.1中不是一个抽象类的概念,而是类的一种设计模式。但实际上可以把Class.create()返回的类看作所有类的共同基类,它在构造函数中调用了一个虚方法initialize,所有继承于它的类都必须实现这个方法,完成构造函数的功能。它们得以实现的本质就是对prototype的操作。

具体代码:

  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
  2. <html>
  3. <head>
  4. <title></title>
  5. <script type="text/javascript" src="js/prototype-1.6.0.3.js"></script>
  6. <script type="text/javascript" src="js/Person.js"></script>
  7. <script type="text/javascript" src="js/Employee.js"></script>
  8. <script type="text/javascript">
  9. //创建一个类
  10. function getEmployeeInfo(){
  11. var employee = new Employee("sunliyuan","Miscofo");
  12. var info = employee.showInfo();
  13. alert(info);
  14. }
  15. </script>
  16. </head>
  17. <body>
  18. <button onclick="getEmployeeInfo()">GetEmployeeInfo</button>
  19. </body>
  20. </html>

父类js:

  1. var Person = Class.create();
  2. Person.prototype={
  3. //必须给初始化值
  4. initialize: function(name) {
  5. this.personName=name;
  6. },
  7. showInfo:function(){
  8. alert(this.personName);
  9. }
  10. }

子类的js:

  1. var Employee = Class.create();
  2. Employee.prototype = Object.extend(new Person(), {
  3. //定义一个抽象类
  4. initialize: function(name,corp) {
  5. this.personName=name;
  6. this.corpName=corp;
  7. },
  8. // corpName:"Micosoft",
  9. showInfo:function(){
  10. return this.personName+","+this.corpName;
  11. }
  12. });
解压密码: detechn或detechn.com

免责声明

本站所有资源出自互联网收集整理,本站不参与制作,如果侵犯了您的合法权益,请联系本站我们会及时删除。

本站发布资源来源于互联网,可能存在水印或者引流等信息,请用户自行鉴别,做一个有主见和判断力的用户。

本站资源仅供研究、学习交流之用,若使用商业用途,请购买正版授权,否则产生的一切后果将由下载用户自行承担。

彻底搞懂泛型
« 上一篇 11-16
用JavaScript实现接口
下一篇 » 11-16

发表评论