JavaScript中实现继承的三种方式和实例


Posted in Javascript onJanuary 29, 2015

javascript虽然是一门面向对象的语言,但是它的继承机制从一开始设计的时候就不同于传统的其他面向对象语言,是基于原型的继承机制,但是在这种机制下,继承依然有一些不同的实现方式。

方法一:类式继承

所谓的类式继承就是指模仿传统面向对象语言的继承方式,继承与被继承的双方都是“类”,代码如下:

首先定义一个父类(或超类):

function Person(name){
    this.name=name;
  }

  Person.prototype.getName=function(){
    return this.name;
  };

该父类person的属性在构造函数中定义,可以保证继承它的子类的name属性不与它共享这个属性,而是单独属于子类,将getName方法挂载到原型上,是为了让继承它的子类的多个实例共享这一个方法体,这样能够节省内存,(对于多个实例来讲,每次New一个实例出来都会保证这些实例的getName方法引用的是同一段内存空间,而不是独立的空间)。

定义一个继承方法extend,如下:

function extend(subClass,superClass){
    var F=function(){};
    F.prototype=superClass.prototype;
    subClass.prototype=new F();
    subClass.prototype.constructor=subClass;

    subClass.superClass=superClass.prototype;
    if(superClass.prototype.constructor==Object.prototype.constructor){
      superClass.prototype.constructor=superClass;
    }

  }

在这个方法中,首先创建一个新的类为F,让它的原型为父类的原型,并且让子类的原型指向该类F的一个实例,从而达到了一个继承父类的目的,同时,子类的原型由于被修改,所以将修改后的原型的constructor属性指向子类,让其拥有构造函数,同时给该子类挂载一个superClass属性,子类可以通过该属性调用父类,从而建立起了子类和父类的关系。

定义一个子类Author来继承父类Person,如下:

function Author(name,books){
    Author.superClass.constructor.call(this,name);
    this.book=books;
  }
  extend(Author,Person);
  Author.prototype.getBooks=function(){
    return this.book;
  }

这里在子类的构造函数中通过其superClass属性调用父类的构造函数,同时采用call方法,转换该方法调用的this指向,让子类Author也拥有(继承)父类的属性,同时子类又拥有自己的属性book,所以在构造函数中将参数books赋值给属性book,达到构造的目的。采用extend函数继承父类Person原型上的属性和方法(实际上只继承了方法,因为我们之前只是将方法挂载到了原型上,属性是在构造函数中定义的)。同时,Author又拥有自己的方法getBooks,将其挂载到对应的原型上,达到了在继承的基础上进一步扩充自身的目的。

这种继承方式很明显就是采用类似于传统面向对象语言的类式继承,优点是对习惯于传统面向对象概念的程序员来讲很容易理解,缺点是过程比较繁琐,内存消耗稍大,因为子类也拥有自己的构造函数及原型,而且子类和父类的属性完全是隔离的,即使两者是一样的值,但是不能共享同一段内存。

方法二:原型式继承

首先定义一个父类,这里不会刻意模仿使用构造函数来定义,而是直接采用对象字面量的方式定义一个对象,该对象就是父类

var Person={
   name:'default name',
   getName:function(){
     return this.name;
   }

 } ;

和第一种方法一样,该对象拥有一个属性name和一个方法getName .

然后再定义一个克隆方法,用来实现子类对父类的继承,如下:

function clone(obj){
     function F(){}
     F.prototype=obj;
     return new F();
   }

该克隆方法新建一个对象,将该对象的原型指向父类即参数obj,同时返回这个对象。

最后子类再通过克隆函数继承父类,如下:

var Author=clone(Person);
 Author.book=['javascript'];
 Author.showBook=function(){
 return this.book;
 }

这里定义一个子类,通过clone函数继承父类Person,同时拓展了一个属性book,和一个方法showBook,这里该子类也拥有属性name,但是它和父类的name值是一样的,所以没有进行覆盖,如果不一样,可以采用

 Author.name='new name';覆盖这个属性,从而得到子类的一个新的name属性值。

这种原型式继承相比于类式继承更为简单自然,同时如果子类的属性和父类属性值相同,可以不进行修改的话,那么它们两者其实共享的是同一段内存空间,如上面的name属性,缺点是对于习惯了传统面向对象的程序员难以理解,如果两者要进行选择的话,无疑是这种方式更为优秀一些。

既然javascript中采用基于原型的方式来实现继承,而且每个对象的原型只能指向某个特定的类的实例(不能指向多个实例),那么如何实现多重继承(即让一个类同时具有多个类的方法和属性,而且本身内部不自己定义这些方法和属性)?

在javascript设计模式中给出了一种掺元类(mixin class)的方式:

首先定义一个掺元类,用来保存一些常用的方法和属性,这些方法和属性可以通过拓展的方式添加到任何其他类上,从而被添加类就具有了该类的某些方法和属性,如果定义多个掺元类,同时添加给一个类,那么该类就是间接实现了“多重继承”,基于这种思想,实现如下:

掺元类定义:

var Mixin=function(){};
  Mixin.prototype={
    serialize:function(){
      var output=[];
      for(key in this){
        output.push(key+":"+this[key]);
      }
      return output.join(',');
    }
  }

该掺元类具有一个serialize方法,用来遍历其自身,输出自身的属性和属性值,并且将他们以字符串形式返回,中间用逗号隔开。

定义一个扩充方法,用来使某个类经过扩充之后具备掺元类的属性或方法,如下:

function augment(receivingClass,givingClass){
    if(arguments[2]){
      for(var i= 2,len=arguments.length;i<len;i++){
        receivingClass.prototype[arguments[i]]=givingClass.prototype[arguments[i]];
      }
    }
    else
    {
      for(methodName in givingClass.prototype){
        if(!receivingClass.prototype[methodName]){
          receivingClass.prototype[methodName]=givingClass.prototype[methodName];
        }
      }

    }
 }

该方法默认是两个参数,第一个参数是接受被扩充的类,第二个参数是掺元类(用来扩充其他类的类),还可以有其他参数,如果大于两个参数,后面的参数都是方法或者属性名,用来表示被扩充类只想继承掺元类的指定的属性或方法,否则默认继承掺元类的所有属性和方法,在该函数中,第一个if分支是用来继承指定属性和方法的情形,else分支是默认继承所有属性和方法的情形。该方法的实质是将掺元类的原型上的属性和方法都扩充(添加)到了被扩充类的原型上面,从而使其具有掺元类的属性和方法。

最后,使用扩充方法实现多重继承

augment(Author,Mixin);
   var author= new Author('js',['javascript design patterns']);
   alert(author.serialize());

这里定义了一个author的类,该类继承自Person父类,同时又具备掺元类Mixin的方法和属性,如果你愿意,可以定义N个掺元类用来扩充该类,它同样能够继承你定义的其他掺元类的属性和方法,这样就实现了多重继承,最后,author的serialize方法的运行结果如下:

JavaScript中实现继承的三种方式和实例

你会发现该类同时具有person类,Author类,Mixin类的属性和方法,其中Person和Mixin的属性和方法都是通过“继承”得来的,从实际上来讲,它实现了多重继承。

Javascript 相关文章推荐
jquery formValidator插件ajax验证 内容不做任何修改再离开提示错误的bug解决方法
Jan 04 Javascript
js+css实现增加表单可用性之提示文字
Jun 03 Javascript
JavaScript中使用Substring删除字符串最后一个字符
Nov 03 Javascript
微信企业号开发之微信考勤Cookies的使用
Sep 11 Javascript
Bootstrap入门书籍之(三)栅格系统
Feb 17 Javascript
javascript和jquery实现用户登录验证
May 04 Javascript
关于javascript事件响应的基础语法总结(必看篇)
Dec 26 Javascript
详解vue-cli 构建Vue项目遇到的坑
Aug 30 Javascript
基于匀速运动的实例讲解(侧边栏,淡入淡出)
Oct 17 Javascript
bootstrap 通过加减按钮实现输入框组功能
Nov 15 Javascript
element-ui的回调函数Events的用法详解
Oct 16 Javascript
vue中promise的使用及异步请求数据的方法
Nov 08 Javascript
javascript面向对象程序设计(一)
Jan 29 #Javascript
jquery调取json数据实现省市级联的方法
Jan 29 #Javascript
JavaScript中实现单体模式分享
Jan 29 #Javascript
angular简介和其特点介绍
Jan 29 #Javascript
javascript实现获取浏览器版本、操作系统类型
Jan 29 #Javascript
浅谈javascript中自定义模版
Jan 29 #Javascript
jQuery和AngularJS的区别浅析
Jan 29 #Javascript
You might like
很好用的PHP数据库类
2009/05/27 PHP
解析thinkphp的左右值无限分类
2013/06/20 PHP
mcrypt启用 加密以及解密过程详细解析
2013/08/07 PHP
php动态添加url查询参数的方法
2015/04/14 PHP
详解PHP+AJAX无刷新分页实现方法
2015/11/03 PHP
PHP使用redis消息队列发布微博的方法示例
2017/06/22 PHP
PHP二维索引数组的遍历实例分析【2种方式】
2019/06/24 PHP
Javascript学习笔记6 prototype的提出
2010/01/11 Javascript
基于JQuery 的消息提示框效果代码
2011/07/31 Javascript
JS获取iframe中marginHeight和marginWidth属性的方法
2015/04/01 Javascript
浅谈JavaScript超时调用和间歇调用
2015/08/30 Javascript
设计模式中的组合模式在JavaScript程序构建中的使用
2016/05/18 Javascript
js实现鼠标左右移动,图片也跟着移动效果
2017/01/25 Javascript
vue-cli如何快速构建vue项目
2017/04/26 Javascript
bootstrap-table组合表头的实现方法
2017/09/07 Javascript
Angular弹出模态框的两种方式
2017/10/19 Javascript
解决layer弹层遮罩挡住窗体的问题
2018/08/17 Javascript
一份超级详细的Vue-cli3.0使用教程【推荐】
2018/11/15 Javascript
Vue实现远程获取路由与页面刷新导致404错误的解决
2019/01/31 Javascript
JavaScript+HTML5 canvas实现放大镜效果完整示例
2019/05/15 Javascript
vant 自定义 van-dropdown-item的用法
2020/08/05 Javascript
Python使用filetype精确判断文件类型
2017/07/02 Python
详解pandas安装若干异常及解决方案总结
2019/01/10 Python
Python连接Oracle之环境配置、实例代码及报错解决方法详解
2020/02/11 Python
Python求凸包及多边形面积教程
2020/04/12 Python
基于FME使用Python过程图解
2020/05/13 Python
CSS3 :not()选择器实现最后一行li去除某种css样式
2016/10/19 HTML / CSS
DHC中国官方购物网站:日本通信销售No.1化妆品
2016/08/20 全球购物
EJB发布WEB服务一般步骤
2012/10/31 面试题
计算机开发个人求职信范文
2013/09/26 职场文书
《天安门广场》教学反思
2014/04/23 职场文书
初二学习计划书范文
2014/04/27 职场文书
委托书的写法
2014/08/30 职场文书
2015年个人现实表现材料
2014/12/10 职场文书
2015年远程教育工作总结
2015/05/20 职场文书
会议开幕致辞怎么写
2016/03/03 职场文书