Walaupun JavaScript adalah bahasa berorientasikan objek, mekanisme pewarisannya berbeza daripada bahasa berorientasikan objek tradisional yang lain sejak awal Ia adalah mekanisme pewarisan berasaskan prototaip, tetapi di bawah mekanisme ini, pewarisan masih Terdapat a beberapa cara yang berbeza untuk melaksanakan ini.
Kaedah 1: Warisan kelas
Apa yang dipanggil warisan kelas merujuk kepada kaedah warisan yang meniru bahasa berorientasikan objek tradisional kedua-dua pewarisan dan yang diwarisi adalah "kelas".
Mula-mula tentukan kelas induk (atau kelas super):
function Person(name){ this.name=name; } Person.prototype.getName=function(){ return this.name; };
Atribut orang kelas induk ditakrifkan dalam pembina, yang memastikan bahawa atribut nama subkelas yang mewarisinya tidak berkongsi atribut ini dengannya, tetapi tergolong dalam subkelas sahaja Kaedah getName dipasang pada prototaip kepada Biarkan berbilang kejadian subkelasnya berkongsi badan kaedah ini, yang boleh menjimatkan memori (Untuk berbilang kejadian, setiap kali kejadian Baharu keluar, ia akan memastikan kaedah getName bagi kejadian ini merujuk kepada ruang memori yang sama. daripada ruang yang berasingan).
Tentukan kaedah pewarisan lanjutan seperti berikut:
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; } }
Dalam kaedah ini, mula-mula buat kelas baharu F, jadikan prototaipnya sebagai prototaip kelas induk, dan biarkan prototaip subkelas menunjuk ke contoh kelas F, dengan itu mencapai tujuan mewarisi kelas induk , pada masa yang sama, kerana prototaip subkelas telah diubah suai, atribut pembina prototaip yang diubah suai dihalakan kepada subkelas, supaya ia mempunyai pembina, dan pada masa yang sama, atribut superClass dipasang pada subkelas, yang melaluinya subkelas boleh memanggil kelas induk , dengan itu mewujudkan hubungan antara subkelas dan kelas induk.
Tentukan Pengarang subkelas untuk mewarisi Orang kelas induk, seperti berikut:
function Author(name,books){ Author.superClass.constructor.call(this,name); this.book=books; } extend(Author,Person); Author.prototype.getBooks=function(){ return this.book; }
Kaedah pewarisan ini jelas menggunakan pewarisan kelas yang serupa dengan bahasa berorientasikan objek tradisional Kelebihannya ialah ia mudah difahami untuk pengaturcara yang terbiasa dengan konsep berorientasikan objek tradisional penggunaan memori adalah lebih besar sedikit , kerana subkelas juga mempunyai pembina dan prototaipnya sendiri, dan sifat subkelas dan kelas induk diasingkan sepenuhnya Walaupun kedua-duanya mempunyai nilai yang sama, mereka tidak boleh berkongsi memori yang sama.
Kaedah 2: Warisan prototaip
Tentukan kelas induk dahulu Kami tidak akan meniru definisi menggunakan pembina Sebaliknya, kami akan terus menggunakan literal objek untuk mentakrifkan objek, iaitu kelas induk
var Person={ name:'default name', getName:function(){ return this.name; } } ;
Kemudian tentukan kaedah klon untuk merealisasikan warisan subkelas daripada kelas induk, seperti berikut:
function clone(obj){ function F(){} F.prototype=obj; return new F(); }
Akhir sekali, subkelas mewarisi kelas induk melalui fungsi klon, seperti berikut:
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方法的运行结果如下:
你会发现该类同时具有person类,Author类,Mixin类的属性和方法,其中Person和Mixin的属性和方法都是通过“继承”得来的,从实际上来讲,它实现了多重继承。