javascript中的继承实现

原文:javascript中的继承实现

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

方法一:类式继承

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

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

1  function Person(name){
2         this.name=name;
3     }
4
5     Person.prototype.getName=function(){
6         return this.name;
7     };

该父类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,如下:

1  function Author(name,books){
2        Author.superClass.constructor.call(this,name);
3        this.book=books;
4    }
5    extend(Author,Person);
6     Author.prototype.getBooks=function(){
7         return this.book;
8     }

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

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

方法二:原型式继承

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

1  var Person={
2       name:'default name',
3       getName:function(){
4           return this.name;
5       }
6
7   }  ;

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

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

1  function clone(obj){
2         function F(){}
3         F.prototype=obj;
4         return new F();
5     }

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

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

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

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

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

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

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

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

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

掺元类定义:

 1 var Mixin=function(){};
 2     Mixin.prototype={
 3         serialize:function(){
 4             var output=[];
 5             for(key in this){
 6                 output.push(key+":"+this[key]);
 7             }
 8             return output.join(',');
 9         }
10     }

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

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

 1  function augment(receivingClass,givingClass){
 2        if(arguments[2]){
 3            for(var i= 2,len=arguments.length;i<len;i++){
 4                receivingClass.prototype[arguments[i]]=givingClass.prototype[arguments[i]];
 5            }
 6        }
 7        else
 8        {
 9            for(methodName in givingClass.prototype){
10                if(!receivingClass.prototype[methodName]){
11                    receivingClass.prototype[methodName]=givingClass.prototype[methodName];
12                }
13            }
14
15        }
16   }

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

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

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

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

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

 

 

时间: 2024-09-08 13:12:06

javascript中的继承实现的相关文章

在JavaScript中实现继承

javascript|继承 JavaScript脚本语言是一种功能强大的面向对象的语言.本文描述了如何在JavaScript中实现继承. Prototype JavaScript没有实现类继承,但可以通过prototype实现.每个JavaScript类中都包含一个prototype对象,当访问一个对象的属性和方法时,它首先从当前对象查找,如果该属性在JavaScript类定义,则直接访问:否则,从类的prototype对象中查找,如果找到则直接访问,否则从prototype的prototype

JavaScript中的继承方式详解

 这篇文章主要介绍了JavaScript中的继承方式详解,本文讲解了js继承的概念.原型式继承与类式继承.原型链继承.类式继承.组合继承.原型式继承等内容,需要的朋友可以参考下     js继承的概念 js里常用的如下两种继承方式: 原型链继承(对象间的继承) 类式继承(构造函数间的继承) 由于js不像java那样是真正面向对象的语言,js是基于对象的,它没有类的概念.所以,要想实现继承,可以用js的原型prototype机制或者用apply和call方法去实现 在面向对象的语言中,我们使用类来

JavaScript中数组继承的简单示例_基础知识

在写一些库时经常会用到树结构的数据,而且一些树形结构的数据对从根到叶的路径获取需求非常高.比如一个站点的整个路由表就是一棵这样的树,它的「路径」实际上就是 URL 中的 path 部分.所以我好几次都用了丧心病狂的数组继承去实现,下面给大家分享下. 在 JavaScript 中,数组也属于 Object 的一种,它也可以继承.任何两个对象本身就可以有继承关系,数组也不例外.于是我们让一个树的任何一个节点都是数组,它只维护自己下标最大的那个元素的值.其它元素的值通过原型继承从祖先节点继承而来.这样

JavaScript中的继承之类继承_javascript技巧

继承简介       在JS中继承是一个非常复杂的话题,比其他任何面向对象语言中的继承都复杂得多.在大多数其他面向对象语言中,继承一个类只需使用一个关键字即可.在JS中想要达到继承公用成员的目的,需要采取一系列措施.JS属于原型式继承,得益于这种灵活性,我们既可以使用标准的基于类的继承,也可以使用更微妙一些的原型式继承.在JS中应该要明确一点,一切继承都是通过prototype来进行的,且JS是基于对象来继承的. 继承: function Animal(name){ this.name = na

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

javascript虽然是一门面向对象的语言,但是它的继承机制从一开始设计的时候就不同于传统的其他面向对象语言,是基于原型的继承机制,但是在这种机制下,继承依然有一些不同的实现方式. 方法一:类式继承 所谓的类式继承就是指模仿传统面向对象语言的继承方式,继承与被继承的双方都是"类",代码如下: 首先定义一个父类(或超类): function Person(name){ this.name=name; } Person.prototype.getName=function(){ retu

Javascript中的继承与原型链理解

在编程语言中,对象并不像真实世界中那样随处可见,随口可以指代.通常我们只有少数的原生对象,剩下的,需要我们自己去创建.在Java语言中,创建一只会"咯咯咯"叫的鸡时,我们是这么做的: public class Chicken{  public void makeSound(){  System.out.println("咯咯咯");  }} Chicken littleChicken = new Chicken(); 先定义一个Chicken类,在Chicken中对

[基础]Javascript中的继承示例代码

面向对象的语言必须具备四个基本特征: 1.封装能力(即允许将基本数据类型的变量或函数放到一个类里,形成类的成员或方法) 2.聚合能力(即允许类里面再包含类,这样可以应付足够复杂的设计) 3.支持继承(父类可以派生出子类,子类拥有父母的属性或方法) 4.支持多态(允许同样的方法名,根据方法签名[即函数的参数]不同,有各自独立的处理方法) 这四个基本属性,javascript都可以支持,所以javascript确实是一种弱类型的面向对象的语言,这里给出一个简单的类继承的代码 <script type

JavaScript中的继承方式详解_javascript技巧

js继承的概念 js里常用的如下两种继承方式: 原型链继承(对象间的继承) 类式继承(构造函数间的继承) 由于js不像java那样是真正面向对象的语言,js是基于对象的,它没有类的概念.所以,要想实现继承,可以用js的原型prototype机制或者用apply和call方法去实现 在面向对象的语言中,我们使用类来创建一个自定义对象.然而js中所有事物都是对象,那么用什么办法来创建自定义对象呢?这就需要用到js的原型: 我们可以简单的把prototype看做是一个模版,新创建的自定义对象都是这个模

关于JavaScript中原型继承中的一点思考_javascript技巧

我们先看一段传统的继承代码: 复制代码 代码如下: //定义超类 function Father(){ this.name = "父亲"; } Father.prototype.theSuperValue = ["NO1","NO2"]; //定义子类 function Child(){ } //实现继承 Child.prototype = new Father(); //修改共享数组 Child.prototype.theSuperValue.