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

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

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

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

有3個原型夷陋,分別處理學(xué)生的姓名欠拾,性別和年齡(當(dāng)然是比較復(fù)雜的處理)胰锌,而我們需要實例化的就是一個學(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ù)各個不同的功能模塊分不同程序員獨立開發(fā)资昧,最后合并起來,實現(xiàn)了多重繼承荆忍。

當(dāng)然如果參數(shù)過多的話可以使用object參數(shù)來做格带。而且各個功能模塊耦合度比較小,出現(xiàn)BUG也能很快定義到功能模塊刹枉,修改其中某一個對其他沒有影響叽唱。

多重繼承小記

此法實現(xiàn)多重繼承,是利用call/apply實現(xiàn)多重繼承嘶卧,核心就是用Function類的call/apply方法去綁定新的類尔觉,使新的類實例化后的對象繼承了該屬性及方法

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

//基類1

function Base1(){

this.name? = "base1";

this.getName = function(){

alert(this.name);

}

};

//基類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為傳進的參數(shù)偽數(shù)組

for(var i=0; i

arguments[i].call(this);

}

}

//實例化一個對象,并繼承自Base1,Base2

var myClass = new Extend(Base1,Base2);

myClass.getName();

myClass.saying();

復(fù)制代碼

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

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

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

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

實例化1就可以完全訪問所有的原型1和原型2的方法钉稍,這里要注意在實例化時不要向原型函數(shù)傳入?yún)?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

這樣通過prototype也實現(xiàn)了多層繼承贡未,不過個人感覺沒有上面多重繼承來的直觀。不過最好的辦法是2者齊上陣蒙袍。

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

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

//基類1

function Base1(){

this.name = "Base1";

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

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

Base1.prototype.getName = function(){

alert(this.name);

};

}

}

//基類2

function Base2(){

this.act = "eating";

this._item = "banana";

//動態(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)建一個類并繼承base1,base2類

var MyClass = extend(Base1,Base2);

//實例化一個對象

var myClass = new MyClass();

myClass.getName();

myClass.saying();

復(fù)制代碼

不過,用prototype繼承還有缺點害幅,就是無法傳遞參數(shù)

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


我們可以做如下2個實驗消恍,以下2個代碼塊充分說明了以上2種模式的優(yōu)劣,其實代碼塊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;

我們來分析一下結(jié)果狠怨,第一種情況,將s1的getName方法存放在實例中邑遏,這樣以后每實例化一個新對象都將生成不同的getName()方法佣赖,而如果將getName()方法添加到s1原型的原型鏈中后(也有人稱之為反射,借鑒與JAVA)记盒,每實例化一個新的對象調(diào)用的都還是同一個getName()方法憎蛤,這樣正是我們所需要的,可以更少的占用內(nèi)存資源提高運行效率纪吮。

如果全部使用prototype方式來進行繼承的話又不能在實例化的同時傳參俩檬,所以兩者混合模式是最常用的方式栏豺,我們看代碼:

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開發(fā)豆胸,頻繁的實例化原型,可以提高運行效率巷疼。

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

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

//基類1

function Base1(name){

this.name = name;

//動態(tài)原型擴展

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

Base1.prototype.getName = function(){

alert(this.name);

};

}

}

//基類2

function Base2(act,_item){

this.act = act;

this._item = _item;

//動態(tài)原型擴展

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];

}

}

}

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

function MyClass(name,act,_item){

Base1.call(this,name);

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

};

//多重繼承類的原型方法

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

//實例化

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

my.saying();

my.getName();

復(fù)制代碼

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

核心代碼如下:

//基類

var Der = function(o){

//私有變量

var name = o.name;

var age = o.age;

var action = function(){

age++;

};

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

var that = {

saying:function(){

action();

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

}

};

//返回對象

return that;

};

//子類

var Panda = function(o){

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

var that = Der(o);

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

var fullName = o.fullName;

that.getFullName = function(){

return fullName;

};

//返回一個對象

return that;

};

//實例化

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ù)制代碼

運行代碼:

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

//基類

var Der = function(o){

//私有變量

var name = o.name;

var age = o.age;

var action = function(){

age++;

};

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

var that = {

saying:function(){

action();

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

}

};

//返回對象

return that;

};

//子類

var Panda = function(o){

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

var that = Der(o);

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

var fullName = o.fullName;

that.getFullName = function(){

return "my fullname is "+fullName;

};

//返回一個對象

return that;

};

//實例化

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ù)制代碼

補充一下:

對于一些私有方法骡尽,比如只想給類調(diào)用不想給實例調(diào)用的方法可以寫在 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都無法直接調(diào)用a這個函數(shù)遣妥。但是這樣會造成內(nèi)存浪費。每實例化一個 s1,函數(shù)a和this.b方法都會占用額外內(nèi)存攀细,所以我們可以這樣改寫:

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ù)和運行環(huán)境,而b方法并沒有因為多次實例化而浪費內(nèi)存谭贪。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末境钟,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子俭识,更是在濱河造成了極大的恐慌慨削,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件套媚,死亡現(xiàn)場離奇詭異缚态,居然都是意外死亡,警方通過查閱死者的電腦和手機堤瘤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門玫芦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人宙橱,你說我怎么就攤上這事姨俩。” “怎么了师郑?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵环葵,是天一觀的道長。 經(jīng)常有香客問我宝冕,道長张遭,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任地梨,我火速辦了婚禮菊卷,結(jié)果婚禮上缔恳,老公的妹妹穿的比我還像新娘。我一直安慰自己洁闰,他們只是感情好歉甚,可當(dāng)我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著扑眉,像睡著了一般纸泄。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上腰素,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天聘裁,我揣著相機與錄音,去河邊找鬼弓千。 笑死衡便,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的洋访。 我是一名探鬼主播镣陕,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼捌显!你這毒婦竟也來了茁彭?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤扶歪,失蹤者是張志新(化名)和其女友劉穎理肺,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體善镰,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡妹萨,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了炫欺。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片乎完。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖品洛,靈堂內(nèi)的尸體忽然破棺而出树姨,到底是詐尸還是另有隱情,我是刑警寧澤桥状,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布帽揪,位于F島的核電站,受9級特大地震影響辅斟,放射性物質(zhì)發(fā)生泄漏转晰。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望查邢。 院中可真熱鬧蔗崎,春花似錦、人聲如沸扰藕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽邓深。三九已至他嫡,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間庐完,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工徘熔, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留门躯,地道東北人。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓酷师,卻偏偏與公主長得像讶凉,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子山孔,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,786評論 2 345

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

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