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 相关文章推荐
疯掉了,尽然有js写的操作系统
Apr 23 Javascript
javascript使用正则获取url上的某个参数
Sep 04 Javascript
jQuery on方法传递参数示例
Dec 09 Javascript
js实现获取两个日期之间所有日期的方法
Jun 17 Javascript
Bootstrap企业网站实战项目4
Oct 14 Javascript
H5移动端适配 Flexible方案
Oct 24 Javascript
vue.js入门(3)——详解组件通信
Dec 02 Javascript
slideToggle+slideup实现手机端折叠菜单效果
May 25 Javascript
深入理解移动前端开发之viewport
Oct 19 Javascript
详解js location.href和window.open的几种用法和区别
Dec 02 Javascript
Node在Controller层进行数据校验的过程详解
Aug 28 Javascript
原生js实现分页效果
Sep 23 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实现无限级分类(不使用递归)
2015/10/22 PHP
Laravel 5.5基于内置的Auth模块实现前后台登陆详解
2017/12/21 PHP
JavaScript的类型简单说明
2010/09/03 Javascript
用jQuery与JSONP轻松解决跨域访问的问题
2014/02/04 Javascript
基于socket.io和node.js搭建即时通信系统
2014/07/30 Javascript
node.js中的Socket.IO使用实例
2014/11/04 Javascript
angularJs关于指令的一些冷门属性详解
2016/10/24 Javascript
微信小程序 绘图之饼图实现
2016/10/24 Javascript
JavaScript拖动层Div代码
2017/03/01 Javascript
基于JavaScript+HTML5 实现打地鼠小游戏逻辑流程图文详解(附完整代码)
2017/11/02 Javascript
Vue.js 2.0和Cordova开发webApp环境搭建方法
2018/02/26 Javascript
在Vue项目中引入腾讯验证码服务的教程
2018/04/03 Javascript
搭建vue开发环境
2018/07/19 Javascript
Layui数据表格之单元格编辑方式
2019/10/26 Javascript
继承行为在 ES5 与 ES6 中的区别详解
2019/12/24 Javascript
nodejs脚本centos开机启动实操方法
2020/03/04 NodeJs
微信小程序搜索框样式并实现跳转到搜索页面(小程序搜索功能)
2020/03/10 Javascript
js中switch语句的学习笔记
2020/03/25 Javascript
Echarts在Taro微信小程序开发中的踩坑记录
2020/11/09 Javascript
python生成随机mac地址的方法
2015/03/16 Python
python遍历数组的方法小结
2015/04/30 Python
Windows下实现将Pascal VOC转化为TFRecords
2020/02/17 Python
详解如何在pyqt中通过OpenCV实现对窗口的透视变换
2020/09/20 Python
用sleep间隔进行python反爬虫的实例讲解
2020/11/30 Python
20行代码教你用python给证件照换底色的方法示例
2021/02/05 Python
加拿大健康、婴儿和美容产品在线购物:Well.ca
2016/11/30 全球购物
美国滑雪和滑雪板商店:Buckman
2018/03/03 全球购物
Penhaligon’s英国官网:成立于1870年的英国香水制造商
2021/02/18 全球购物
党的群众路线教育实践活动心得体会900字
2014/03/07 职场文书
领导干部保密承诺书
2014/08/30 职场文书
导航工程专业自荐信
2014/09/02 职场文书
师范生免费教育协议书范本
2014/10/09 职场文书
街道务虚会发言材料
2014/10/20 职场文书
县级领导干部开展党的群众路线教育实践活动工作汇报
2014/10/25 职场文书
2015年度党风廉政建设工作情况汇报
2015/01/02 职场文书
Django + Taro 前后端分离项目实现企业微信登录功能
2022/04/07 Python