日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

深入浅出理解Javascript原型概念以及继承机制(转)

發(fā)布時間:2025/7/25 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 深入浅出理解Javascript原型概念以及继承机制(转) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

在Javascript語言中,原型是一個經(jīng)常被討論到但是有非常讓初學(xué)者不解的概念。那么,到底該怎么去給原型定義呢?不急,在了解是什么之前,我們不妨先來看下為什么。

Javascript最開始是網(wǎng)景公司的死直男工程師Brendan Eich負責(zé)開發(fā)。起初設(shè)計的意愿非常簡單,網(wǎng)景公司在1994年發(fā)布了Navigator瀏覽器0.9版(歷史上第一個比較成熟的網(wǎng)絡(luò)瀏覽器),這時候需要一個網(wǎng)頁腳本語言,使得瀏覽器可以與網(wǎng)頁互動。Brendan Eich認為這種語言無需復(fù)雜,盡量簡單。然而Javascript里面都是對象,必須有一種機制,將所有對象聯(lián)系起來,這就需要設(shè)計一個繼承機制。為了維持Javascript的簡單,Eich拋棄了傳統(tǒng)面向?qū)ο笳Z言中類的設(shè)計,而使用構(gòu)造函數(shù)的方式去實現(xiàn)繼承。比如下面一個構(gòu)造函數(shù):

1 function Stark(name){ 2  this.name = name; 3 }

咳咳,為什么是Stark?因為博主是個骨灰級的冰與火之歌NC粉(●′艸`)ヾ 好好好言歸正傳,那么當(dāng)我們要創(chuàng)建一個新的Stark對象時,僅需調(diào)用一個new命令:

1 var branStark = new Stark('布蘭'); 2 console.log(branStark .name); // 布蘭

然而這種繼承方式有個最大的缺點,便是無法實現(xiàn)數(shù)據(jù)和方法的共享。比如

1 function Stark(name){2  this.name = name;3  this.words = 'Winter is coming. ';4 }5 var branStark = new Stark('布蘭');6 var aryaStark = new Stark('艾莉亞');7 Stark.words = 'Summer is coming.'8 9 console.log(branStark.words); //Winter is coming. 10 console.log(aryaStark.words); //Winter is coming.

可以看到,當(dāng)Stark改變了家族族語words屬性,布蘭和艾莉亞的族語并沒有改變。這是因為他們都有自己的一個Stark屬性和方法副本。有時候這是好事,不會造成父子類數(shù)據(jù)上的混亂,但是有時候我們需要統(tǒng)一規(guī)劃,使子類之間有數(shù)據(jù)的共享(大家一個家族的為毛不共用一個族語啊(╯‵□′)╯︵┻━┻ ),也節(jié)約資源上的開銷。因此,Eich提出了一個概念:原型(prototype)。他為構(gòu)造函數(shù)設(shè)置一個prototype屬性。prototype屬性包含一個對象,所有實例對象需要共享的屬性和方法,都放在這個對象里面;那些不需要共享的屬性和方法,就放在構(gòu)造函數(shù)里面。實例對象一旦創(chuàng)建,將自動引用prototype對象的屬性和方法。也就是說,實例對象的屬性和方法,分成兩種,一種是本地的,另一種是引用的。

1 function Stark(name){2  this.name = name;3 }4 Stark.prototype.words = 'Winter is coming.';5 6 var branStark = new Stark('布蘭');7 var aryaStark = new Stark('艾莉亞');8 9 console.log(branStark.words); //Winter is coming. 10 console.log(aryaStark.words); //Winter is coming. 11 12 Stark.prototype.words = 'Summer is coming.'; 13 console.log(branStark.words); //Summer is coming. 14 console.log(aryaStark.words); //Summer is coming.

可以看到,當(dāng)Stark改變了words屬性,布蘭和艾莉亞的words屬性也跟著改變了。這就實現(xiàn)了整齊劃一~

通過以上介紹,大家應(yīng)該對Javascript中的prototype概念有了比較基礎(chǔ)的了解。但是在實際應(yīng)用中,從父類繼承創(chuàng)建一個子類,還是沒那么簡單。子類有時候希望擁有自己的構(gòu)造函數(shù),這時候上面例子整齊劃一的方法就不適用了。那么該如何保證子類既能繼承父類的方法,又能保留自己的特色呢?別急,首先我們需要更深入一點,了解一下原型鏈(prototype chain)的概念。

簡單整理一下構(gòu)造函數(shù),原型和實例之間的關(guān)系:“每個構(gòu)造函數(shù)都有一個原型對象,原型對象都包含一個指向構(gòu)造函數(shù)的指針,而實例都包含一個指向原型對象的內(nèi)部指針”。好,那我們看下以下代碼:

1 function Stark (){2 this.words = 'Winter is coming.'; 3 }4 function BranStark(){5 this.pet = 'Summer'; 6 }7 function Summer(){8 this.favor = 'meat';9 } 10 BranStark.prototype = new Stark(); 11 Summer.prototype = new BranStark(); 12 13 summer = new Summer(); 14 15 console.log(summer.favor); //meat 16 console.log(summer.pet); //Summer 17 console.log(summer.words); //Winter is coming. 以上展示一個原型鏈繼承的效果。我們讓Summer的原型對象等于BranStark的實例,而BranStark的實例中包含一個指向BranStark原型對象的內(nèi)部指針;而BranStark的原型對象又等于Stark的實例,Stark的實例中包含一個指向Stark原型對象的內(nèi)部指針。這種關(guān)系可以層層遞進,形成一條實例與原型的鏈條,這就是原型鏈。我在網(wǎng)上找了個圖,大概是這樣:

在JS中實現(xiàn)繼承,大概有兩種思路:一個就是我們一開始所講的使用構(gòu)造函數(shù);另一個就是上面例子所講述的原型鏈繼承。但兩者各有利弊,構(gòu)造函數(shù)繼承會造成資源的浪費,方法和數(shù)據(jù)難以復(fù)用;原型鏈繼承當(dāng)有包含引用類型值的原型時,則容易造成數(shù)據(jù)上的混亂。請看下面例子:

1 function Stark (){ }2 Stark.prototype.words = ['Winter is coming'];3 function BranStark(){4  this.name = '布蘭';5 }6 function AryaStark(){7  this.name = '艾莉亞';8 }9 10 BranStark.prototype = new Stark(); 11 AryaStark.prototype = new Stark(); 12 13 aryaStark = new AryaStark(); 14 console.log(aryaStark.words); //['Winter is coming.'] 15 aryaStark.words.push('Needle is good.'); 16 console.log(aryaStark.words); //['Winter is coming.', 'Needle is good.'] 17 18 branStark = new BranStark(); 19 console.log(branStark.words); //['Winter is coming.', 'Meat is good.']

?可以看到當(dāng)原型內(nèi)包含引用類型值時,子類實例aryaStark對words屬性做出修改后,連其他子類也受到影響啦!Σ(  ̄д ̄;)艾莉亞你這個坑爹貨!!咳,回顧下我們一開始所得到的結(jié)論:在實現(xiàn)繼承的時候,所有實例對象需要共享的屬性和方法,可以放在prototype對象里面;那些不需要共享的屬性和方法,就放在構(gòu)造函數(shù)里面。所以為了避免艾莉亞這種調(diào)皮孩子亂搗蛋,我們可以稍微做點改進!

1 function Stark (){2 this.words = ['Winter is coming.']; 3 }4 function BranStark(){5  this.name = '布蘭';6 }7 function AryaStark(){8  this.name = '艾莉亞';9 } 10 11 BranStark.prototype = new Stark(); 12 BranStark.prototype.constructor = BranStark; 13 AryaStark.prototype = new Stark(); 14 AryaStark.prototype.constructor = AryaStark; 15 16 aryaStark = new AryaStark(); 17 console.log(aryaStark.words); //['Winter is coming.'] 18 aryaStark.words.push('Needle is good.'); 19 console.log(aryaStark.words); //['Winter is coming.', 'Needle is good.'] 20 21 branStark = new BranStark(); 22 console.log(branStark.words); //['Winter is coming.']

?_(:з」∠)_于是這樣, 把需要被保護的數(shù)據(jù)放在構(gòu)造函數(shù)就OK了,子類之間既能共享數(shù)據(jù)又能保證安全。這種繼承方式也叫組合繼承,是JS最常見的一種。注意到我增加了兩行代碼:

1 BranStark.prototype.constructor = BranStark; 2 AryaStark.prototype.constructor = AryaStark;

解釋下為什么:當(dāng)我們把一個構(gòu)造函數(shù)的prototype對象賦值給一個實例,我們相當(dāng)于把該prototype對象完全刪除,賦予一個新值。而每一個prototype對象都有一個constructor屬性,指向它的構(gòu)造函數(shù)。重新賦值后,constructor屬性被改變,改為指向父類的構(gòu)造函數(shù)。所以為了不會導(dǎo)致繼承鏈的紊亂,我們需要手動把原型對象的構(gòu)造函數(shù)指針重新指向自己。

好了終于寫完了,希望大家看得明白!\( ̄▽ ̄)/

原文鏈接:http://www.cnblogs.com/waitforwind/p/3674766.html

轉(zhuǎn)載于:https://www.cnblogs.com/wmlunge/p/3679525.html

總結(jié)

以上是生活随笔為你收集整理的深入浅出理解Javascript原型概念以及继承机制(转)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。