Javascript實(shí)現(xiàn)多重繼承、多層繼承以及混合繼承

轉(zhuǎn)自:360圖書(shū)館 ??時(shí)間:2016-9-26

原標(biāo)題:使用Javascript,可以實(shí)現(xiàn)多層繼承

1.javascript的繼承1:多重繼承

有3個(gè)原型,分別處理學(xué)生的姓名,性別和年齡(當(dāng)然是比較復(fù)雜的處理),而我們需要實(shí)例化的就是一個(gè)學(xué)生的原型,于是多重繼承誕生了,我們看代碼:

var s1 = function(name){

this.name = name;

}

var s2 = function(sex){

this.sex = sex;

}

var s3 = function(age){

this.age = age;

}

var Student = function(name, sex, age, score){

s1.call(this, name);

s2.call(this, sex);

s3.call(this, age);

this.score = score;

}

Student.prototype.constructor = Student;

var s = new Student('jack', 'male', '12', '100');

alert(s.name);//jack

alert(s.sex);//male

alert(s.age);//12

alert(s.score);//100

這樣我們就可以根據(jù)各個(gè)不同的功能模塊分不同程序員獨(dú)立開(kāi)發(fā),最后合并起來(lái),實(shí)現(xiàn)了多重繼承。

當(dāng)然如果參數(shù)過(guò)多的話(huà)可以使用object參數(shù)來(lái)做。而且各個(gè)功能模塊耦合度比較小,出現(xiàn)BUG也能很快定義到功能模塊,修改其中某一個(gè)對(duì)其他沒(méi)有影響。

多重繼承小記

此法實(shí)現(xiàn)多重繼承,是利用call/apply實(shí)現(xiàn)多重繼承,核心就是用Function類(lèi)的call/apply方法去綁定新的類(lèi),使新的類(lèi)實(shí)例化后的對(duì)象繼承了該屬性及方法

/*-------利用call/apply實(shí)現(xiàn)多重繼承--------*/

//基類(lèi)1

function Base1(){

this.name? = "base1";

this.getName = function(){

alert(this.name);

}

};

//基類(lèi)2

function Base2(){

this.act = "eating";

this._item = "banana";

this.saying = function(){

alert("I'm "+this.act+" the "+this._item+"!");

};

};

//利用call/apply多重繼承

function Extend(){

//arguments為傳進(jìn)的參數(shù)偽數(shù)組

for(var i=0; i

arguments[i].call(this);

}

}

//實(shí)例化一個(gè)對(duì)象,并繼承自Base1,Base2

var myClass = new Extend(Base1,Base2);

myClass.getName();

myClass.saying();

復(fù)制代碼

但它的缺點(diǎn)是基類(lèi)的方法只能定義在類(lèi)中,這樣在每次實(shí)例化的時(shí)候都會(huì)創(chuàng)建該方法,造成多余內(nèi)存占用

2、javascript的繼承2:原型鏈多層繼承

原型鏈就是利用prototype屬性來(lái)實(shí)現(xiàn)的,例如:原型1.prototype = new 原型2() ;

這樣就可以利用實(shí)例化1 = new 原型1();

實(shí)例化1就可以完全訪問(wèn)所有的原型1和原型2的方法,這里要注意在實(shí)例化時(shí)不要向原型函數(shù)傳入?yún)?shù),參數(shù)需要在實(shí)例化以后再定義。

var s1 = function(){

}

s1.prototype.getName = function(){alert(this.name)};

var s2 = function(){

}

s2.prototype =new s1();

s2.prototype.constructor = s2;

s2.prototype.getSex = function(){alert(this.sex)};

var s3 = function(){

}

s3.prototype = new s2();

s3.prototype.constructor = s3;

s3.prototype.getAge = function(){alert(this.age)};

var s = new s3();

s.name = 'jack';

s.sex = 'male';

s.age = '22';

s.getName();//jack

s.getSex();//male

s.getAge();//22

這樣通過(guò)prototype也實(shí)現(xiàn)了多層繼承,不過(guò)個(gè)人感覺(jué)沒(méi)有上面多重繼承來(lái)的直觀。不過(guò)最好的辦法是2者齊上陣。

針對(duì)多余內(nèi)存被占用,所以第二種方法是用prototype原型的形式來(lái)完成多重繼承

/*-------利用prototype實(shí)現(xiàn)多重繼承--------*/

//基類(lèi)1

function Base1(){

this.name = "Base1";

//動(dòng)態(tài)原型模式

if(typeof this.getName !== "function"){

Base1.prototype.getName = function(){

alert(this.name);

};

}

}

//基類(lèi)2

function Base2(){

this.act = "eating";

this._item = "banana";

//動(dòng)態(tài)原型模式

if(typeof this.getName !== "function"){

Base2.prototype.saying=function(){

alert("I'm "+this.act+" the "+this._item+"!");

};

}

};

//利用prototype多重繼承;

function extend(){

var Class = function(){};

for(var i=0; i

var base = new arguments[i]();

for(var j in base){

Class.prototype[j] = base[j];

}

};

return Class;

}

//創(chuàng)建一個(gè)類(lèi)并繼承base1,base2類(lèi)

var MyClass = extend(Base1,Base2);

//實(shí)例化一個(gè)對(duì)象

var myClass = new MyClass();

myClass.getName();

myClass.saying();

復(fù)制代碼

不過(guò),用prototype繼承還有缺點(diǎn),就是無(wú)法傳遞參數(shù)

3.javascript的繼承3:混合模式繼承


我們可以做如下2個(gè)實(shí)驗(yàn),以下2個(gè)代碼塊充分說(shuō)明了以上2種模式的優(yōu)劣,其實(shí)代碼塊2已經(jīng)是混合模式了。

代碼塊1:var s1 = function(name){

this.name = name;

this.getName = function(){

alert(this.name);

}

}

var o1 = new s1('jack');

var o2 = new s1('marry');

alert(o1.getName === o2.getName);//false;

代碼塊2:var s1 = function(name){

this.name = name;

}

s1.prototype.getName = function(){

alert(this.name);

}

var o1 = new s1('jack');

var o2 = new s1('marry');

alert(o1.getName === o2.getName);//true;

我們來(lái)分析一下結(jié)果,第一種情況,將s1的getName方法存放在實(shí)例中,這樣以后每實(shí)例化一個(gè)新對(duì)象都將生成不同的getName()方法,而如果將getName()方法添加到s1原型的原型鏈中后(也有人稱(chēng)之為反射,借鑒與JAVA),每實(shí)例化一個(gè)新的對(duì)象調(diào)用的都還是同一個(gè)getName()方法,這樣正是我們所需要的,可以更少的占用內(nèi)存資源提高運(yùn)行效率。

如果全部使用prototype方式來(lái)進(jìn)行繼承的話(huà)又不能在實(shí)例化的同時(shí)傳參,所以?xún)烧呋旌夏J绞亲畛S玫姆绞剑覀兛创a:

var s1 = function(name){

this.name = name;

}

s1.prototype.getName = function(){alert(this.name)};

var s2 = function(sex){

this.sex = sex;

}

s2.prototype =new s1();

s2.prototype.getSex = function(){alert(this.sex)};

var s3 = function(age){

this.age = age

}

s3.prototype = new s2();

s3.prototype.getAge = function(){alert(this.age)};

var s4 = function(name, sex, age){

s1.call(this, name);

s2.call(this, sex);

s3.call(this, age);

}

s4.prototype = new s3();

s4.prototype.constructor = s4;

var s = new s4('jack', 'male', '25');

s.getName();//jack

s.getSex();//male

s.getAge();//25

這樣3重常用的繼承方法介紹完畢了,混合模式適合一些比較大型javascript開(kāi)發(fā),頻繁的實(shí)例化原型,可以提高運(yùn)行效率。

使用了兩種混合的方法,擁有各自的優(yōu)點(diǎn)

/*-------混合型實(shí)現(xiàn)多重繼承--------*/

//基類(lèi)1

function Base1(name){

this.name = name;

//動(dòng)態(tài)原型擴(kuò)展

if(typeof this.getName !== "function"){

Base1.prototype.getName = function(){

alert(this.name);

};

}

}

//基類(lèi)2

function Base2(act,_item){

this.act = act;

this._item = _item;

//動(dòng)態(tài)原型擴(kuò)展

if(typeof this.saying!== "function"){

Base2.prototype.saying=function(){

alert("I'm "+this.act+" the "+this._item+"!");

};

}

};

//原型多重繼承

function prototypeExtend(){

for(var i=0; i

var base = new arguments[i]();

for(var j in base){

this.prototype[j] = base[j];

}

}

}

//定義一個(gè)類(lèi),內(nèi)部用call/apply繼承

function MyClass(name,act,_item){

Base1.call(this,name);

Base2.apply(this,[act,_item]);

};

//多重繼承類(lèi)的原型方法

prototypeExtend.apply(MyClass,[Base1,Base2]);

//實(shí)例化

var my = new MyClass("Der","eating","apple");

my.saying();

my.getName();

復(fù)制代碼

上面的方法構(gòu)造出來(lái)的實(shí)例的屬性都無(wú)法實(shí)現(xiàn)私有,另一種函數(shù)化返回對(duì)象來(lái)實(shí)現(xiàn)繼承模式,則可以很好的利用閉包在函數(shù)內(nèi)部實(shí)現(xiàn)私有變量。

核心代碼如下:

//基類(lèi)

var Der = function(o){

//私有變量

var name = o.name;

var age = o.age;

var action = function(){

age++;

};

//創(chuàng)建一個(gè)對(duì)象,可訪問(wèn)內(nèi)部私有變量

var that = {

saying:function(){

action();

return "I'm "+name+",i am "+age+" years old!";

}

};

//返回對(duì)象

return that;

};

//子類(lèi)

var Panda = function(o){

//創(chuàng)建一個(gè)對(duì)象繼承自Der

var that = Der(o);

//私有變量(差異化設(shè)置)

var fullName = o.fullName;

that.getFullName = function(){

return fullName;

};

//返回一個(gè)對(duì)象

return that;

};

//實(shí)例化

var der = Der({"name":"der","age":26});

document.writeln(der.saying()+"
");

var panda = Panda({"name":"panda","fullName":"zhengPanda","age":25});

document.writeln(panda.saying()+"
");

document.writeln(panda.getFullName()+"
");

復(fù)制代碼

運(yùn)行代碼:

函數(shù)化對(duì)象繼承(帶私有變量)

//基類(lèi)

var Der = function(o){

//私有變量

var name = o.name;

var age = o.age;

var action = function(){

age++;

};

//創(chuàng)建一個(gè)對(duì)象,可訪問(wèn)內(nèi)部私有變量

var that = {

saying:function(){

action();

return "I'm "+name+",i am "+age+" years old!";

}

};

//返回對(duì)象

return that;

};

//子類(lèi)

var Panda = function(o){

//創(chuàng)建一個(gè)對(duì)象繼承自Der

var that = Der(o);

//私有變量(差異化設(shè)置)

var fullName = o.fullName;

that.getFullName = function(){

return "my fullname is "+fullName;

};

//返回一個(gè)對(duì)象

return that;

};

//實(shí)例化

var der = Der({"name":"der","age":26});

document.writeln(der.saying()+"
");

var panda = Panda({"name":"panda","fullName":"zhengPanda","age":25});

document.writeln(panda.saying()+"
");

document.writeln(panda.getFullName()+"
");

復(fù)制代碼

補(bǔ)充一下:

對(duì)于一些私有方法,比如只想給類(lèi)調(diào)用不想給實(shí)例調(diào)用的方法可以寫(xiě)在 function 內(nèi)部:

例如:var s1 = function(){

var a = function(){

...

}

this.b = function(){}

}

var x = new s1();

var y = new s1();

alert(x.b === y.b) //false這樣y和x都無(wú)法直接調(diào)用a這個(gè)函數(shù)。但是這樣會(huì)造成內(nèi)存浪費(fèi)。每實(shí)例化一個(gè) s1,函數(shù)a和this.b方法都會(huì)占用額外內(nèi)存,所以我們可以這樣改寫(xiě):

var s1 =function(){

function a(){

...

}

return function(){

this.b = function(){}

}

}

var x = new s1();

var y = new s1();

alert(x.b === y.b) //true;

于是,這樣a方法可以拿到實(shí)例化時(shí)的參數(shù)和運(yùn)行環(huán)境,而b方法并沒(méi)有因?yàn)槎啻螌?shí)例化而浪費(fèi)內(nèi)存。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,345評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,494評(píng)論 3 416
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 176,283評(píng)論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 62,953評(píng)論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,714評(píng)論 6 410
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,186評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,410評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,940評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,776評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,976評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評(píng)論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,210評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,642評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 35,878評(píng)論 1 286
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,654評(píng)論 3 391
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,958評(píng)論 2 373

推薦閱讀更多精彩內(nèi)容

  • 一、理解對(duì)象 1.創(chuàng)建 ①構(gòu)造函數(shù) new Object ②對(duì)象字面量 var o = {}; 2.屬性類(lèi)型 ①數(shù)...
    duJing閱讀 425評(píng)論 0 0
  • 工廠模式類(lèi)似于現(xiàn)實(shí)生活中的工廠可以產(chǎn)生大量相似的商品,去做同樣的事情,實(shí)現(xiàn)同樣的效果;這時(shí)候需要使用工廠模式。簡(jiǎn)單...
    舟漁行舟閱讀 7,798評(píng)論 2 17
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法,類(lèi)相關(guān)的語(yǔ)法,內(nèi)部類(lèi)的語(yǔ)法,繼承相關(guān)的語(yǔ)法,異常的語(yǔ)法,線程的語(yǔ)...
    子非魚(yú)_t_閱讀 31,717評(píng)論 18 399
  • Chapter 6 面向?qū)ο蟮某绦蛟O(shè)計(jì) 理解對(duì)象 使用對(duì)象字面量語(yǔ)法創(chuàng)建對(duì)象var person = { n...
    云之外閱讀 596評(píng)論 0 1
  • 單例模式 適用場(chǎng)景:可能會(huì)在場(chǎng)景中使用到對(duì)象,但只有一個(gè)實(shí)例,加載時(shí)并不主動(dòng)創(chuàng)建,需要時(shí)才創(chuàng)建 最常見(jiàn)的單例模式,...
    Obeing閱讀 2,085評(píng)論 1 10