瞎扯.javascript面向?qū)ο?/h2>

已經(jīng)忘了多久沒拿起javascirpt的書本了,無聊中拾起快被我遺忘在角落的書本<javascript高級(jí)程序設(shè)計(jì)>。

尼古拉斯竟然把這么奇葩的js面向?qū)ο笳f的這么好

從最原始的工廠模板說起

function createPerson(name,age){

?var o = new Object();

?o.name = name;

?o.age = age;

o.sayName = function(){

? console.log(this.name);

}

?return o;

}

這樣,but...等等,如何知道創(chuàng)建的對(duì)象是什么類型的?

構(gòu)造函數(shù)模式

function Person(name,age){

this.name = name;

this.age = age;

this.sayName = function(){

}

var person1 = new Person("三毛",25);

簡(jiǎn)潔了不少,問題又來了:難道我每次new一個(gè)對(duì)象,就要重新創(chuàng)建個(gè)sayName函數(shù)嗎?為什么這么說?

函數(shù)也是對(duì)象,每次實(shí)例化Person時(shí),都會(huì)實(shí)例化一個(gè)sayName Function。也就是說:每個(gè)Person的示例,都有一個(gè)不同的sayName Function實(shí)例。何必如此?

理解原型模式

原型模式很好的解決了上述問題,這么說吧,每個(gè)function都有一個(gè)prototype屬性(我們叫原型),指向一個(gè)原型對(duì)象。

所以,我們可以把公共的方法屬性都加到它上面。

function Person(){

}

Person.prototype.name = "三毛";

Person.prototype.age = 25;

Person.prototype.sayName = function(){

?console.log(this.name);

}

把屬性方法加到了函數(shù)的prototype(實(shí)際上也是個(gè)對(duì)象)上,后續(xù)創(chuàng)建的實(shí)例對(duì)象都從這個(gè)原型對(duì)象上繼承了屬性和方法。

然而,它也不是完美的。原型對(duì)象的問題也是顯而易見的:由于所有的實(shí)例都是共享原型對(duì)象的方法屬性,那么意思就是說所有的實(shí)例共享了一份屬性方法!那創(chuàng)建的實(shí)例還有個(gè)毛用?

聯(lián)想到前面我們提過的構(gòu)造函數(shù)模式,我們可以把構(gòu)造函數(shù)+原型模式結(jié)合起來。

構(gòu)造函數(shù)負(fù)責(zé)自有的屬性,而原型對(duì)象負(fù)責(zé)公共的方法,一種新的模式應(yīng)運(yùn)而生:

組合模式

Person.prototype.sayName = function(){

console.log(this.name);

}

完美解決了構(gòu)造函數(shù)模式和原型模式的問題。

再談?wù)刯avascript繼承

在“理解原型模式”中,已經(jīng)談到了js的原型模式,而js的繼承就是依靠原型鏈來實(shí)現(xiàn)的。

js原型鏈

我們來簡(jiǎn)單回顧下前面講過的內(nèi)容:

1 每個(gè)構(gòu)造函數(shù)都有一個(gè)原型對(duì)象;

2 原型對(duì)象包含一個(gè)指向構(gòu)造函數(shù)的指針(證明自己是從哪來的);

3 構(gòu)造函數(shù)的實(shí)例(這么說可能有點(diǎn)不準(zhǔn)確)包含一個(gè)指向原型對(duì)象的指針。

有點(diǎn)暈,感覺有點(diǎn)像三角戀,看個(gè)實(shí)例:

function SuperType(){

this.property = true;

}

SuperType.prototype.getSuperValue = function(){

?return this.property;

}

function SubType(){

?this.subproperty = false;

}

//繼承,使SubType的原型指向SuperType的原型

SubType.prototype = new SuperType();

SubType.prototype.getSubValue = function(){

?return this.subproperty;

}

var instance = new SubType();

console.log(instance.getSuperValue());//true,實(shí)際上是SuperType的值

看以看出,單獨(dú)使用原型鏈實(shí)現(xiàn)繼承,實(shí)際上生成的實(shí)例都是共享一份屬性或者方法的。

那么,實(shí)例就沒有意義了。

那如果借用構(gòu)造函數(shù)呢?

我們知道,構(gòu)造函數(shù)只能實(shí)現(xiàn)對(duì)實(shí)例屬性的繼承,沒辦法實(shí)現(xiàn)方法的繼承,所以如果單獨(dú)使用構(gòu)造函數(shù)模式,方法就需要都寫在構(gòu)造函數(shù)里面,函數(shù)復(fù)用就無從談起了。

組合繼承

組合繼承借用了原型鏈實(shí)現(xiàn)原型屬性和方法的繼承,又可以通過構(gòu)造函數(shù)實(shí)現(xiàn)實(shí)例屬性的繼承??梢哉f既實(shí)現(xiàn)了函數(shù)復(fù)用,又保證每個(gè)實(shí)例都有自己的屬性。

function SuperType(name){

?this.name = name;

?this.colors = ["red", "blue"];

}

SuperType.prototype.sayName = function(){

?console.log(this.name);

}

function SubType(name,age){

?SuperType.call(this,name);//在當(dāng)前實(shí)例環(huán)境下執(zhí)行SuperType構(gòu)造函數(shù)->2

?this.age = age;

}

SubType.prototype = new SuperType();//->1

SubType.prototype.sayAge = function(){

?console.log(this.age);

}

看以看到,這種模式結(jié)合了兩者的優(yōu)點(diǎn),又彌補(bǔ)了相互的不足??梢哉f,是一種不錯(cuò)的用于實(shí)現(xiàn)繼承的方法。

但是,這種方法并不是最好的,我們來詳細(xì)看一下:

1 為了實(shí)現(xiàn)繼承,第一點(diǎn)調(diào)用了SuperType的構(gòu)造函數(shù),這樣SubType.prototype繼承了兩個(gè)屬性

2 SubType構(gòu)造函數(shù)內(nèi)部,又調(diào)用了一次SubType構(gòu)造函數(shù),顯得有些多余了

寄生組合繼承

通過借用構(gòu)造函數(shù)來繼承屬性,通過原型鏈來繼承方法。

function object(super){

?var func = function(){};

?func.prototype = super;

?var o = new func();

?return o;

}

function inheritPrototype(sub,super){

?var prototype = object(super.prototype);

?prototype.constructor = sub;

?sub.prototype = prototype;

}

這是寄生組合繼承的簡(jiǎn)單形式。

通過接受子構(gòu)造函數(shù)和父構(gòu)造函數(shù),第一步創(chuàng)建父類型原型的一個(gè)副本;

第二步為副本添加constructor屬性,最后再把新的原型賦給子原型,完美實(shí)現(xiàn)了繼承關(guān)系。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容