您好,登錄后才能下訂單哦!
這篇文章給大家分享的是有關(guān)JS原型鏈的示例分析的內(nèi)容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。
一、題目
下面程序運行結(jié)果是什么?
function Animal() { this.name = 'Animal'; } Animal.prototype.changeName = function (name) { this.name = name; } function Cat() { this.name = 'Cat'; } var animal = new Animal(); Cat.prototype = animal; Cat.prototype.constructor = Cat; var cat = new Cat(); animal.changeName('Tiger'); console.log(cat.name)
A. Animal
B. Cat
C. Tiger
D. 都不是
答案是 B Cat
二、解讀
1. 原型對象
無論什么時候,只要創(chuàng)建了一個新函數(shù),就會根據(jù)一組特定的規(guī)則為該函數(shù)創(chuàng)建一個prototype屬性,這個屬性指向函數(shù)的原型對象。在默認情況下,所有的原型對象都會自動獲得一個constructor(構(gòu)造函數(shù))屬性,這個屬性是一個指向prototype屬性所在函數(shù)的指針。
下面用圖來說明
function Animal() { this.name = 'Animal'; } Animal.prototype.changeName = function (name) { this.name = name; }
首先創(chuàng)建了一個Animal函數(shù),Animal中含有一個prototype屬性,指向Animal Prototype,而Animal.prototype.constructor指向Animal。這個時候由于name屬性是在函數(shù)中定義的,所以不在Animal Prototype中,而changeName 函數(shù)是通過Animal.prototype.changeName定義的,所以我們可以通過這種方式,在實例化多個對象時,共享原型所保存的方法。
同理,當(dāng)創(chuàng)建了Cat函數(shù)時,也是一樣。
function Cat() { this.name = 'Cat'; }
2. 創(chuàng)建實例
當(dāng)調(diào)用構(gòu)造函數(shù)創(chuàng)建一個新實例后,該實例的內(nèi)部將包含一個指針(內(nèi)部屬性),指向構(gòu)造函數(shù)的原型對象。在ECMA-262第5版中管這個指針叫[[Prototype]]。雖然在腳本中沒有標(biāo)準(zhǔn)的方式訪問[[Prototype]],但Firefox、Safari和Chrome在每個對象上都支持一個屬性__proto__。明確重要的一點,這個連接存在于實例與構(gòu)造函數(shù)的原型對象之間,而不是存在于實例與構(gòu)造函數(shù)之間。
// 將Cat的原型對象指向animal實例,獲得animal中的屬性,原有的屬性丟失 Cat.prototype = animal;
這一部分相當(dāng)于是把Cat的原型對象的指針指向了animal實例,所以原來Cat原型對象中的constructor屬性丟失,替換成了animal實例中的屬性,包括name屬性以及__proto__內(nèi)部屬性,同時__proto__屬性也指向Animal.prototype,因此Cat也可以通過原型鏈查找調(diào)用到Animal中的屬性和方法。
// 相當(dāng)于重新創(chuàng)建了constructor,指向Cat構(gòu)造函數(shù) Cat.prototype.constructor = Cat;
這一部分相當(dāng)于是重新在原型對象中創(chuàng)建了一個constructor屬性,同時指向Cat構(gòu)造函數(shù)。
var cat = new Cat(); // 實例化一個Cat對象,跟實例化Animal相似
3. 調(diào)用方法
animal.changeName('Tiger');
當(dāng)var animal = new Animal();實例化了一個Animal對象后,animal都包含一個內(nèi)部屬性,該屬性指向了Animal.prototype;換句話說,animal與構(gòu)造函數(shù)Animal沒有直接的關(guān)系??墒?,可以看到雖然在實例中不含changeName,但我們卻可以調(diào)用animal.changeName(name),這是通過查找對象屬性的過程來實現(xiàn)的,即:
首先查找實例中實例中animal是否有changeName方法,如果沒有則繼續(xù)尋找,去到Animal.prototype尋找是否有changeName方法,如果有則調(diào)用,沒有則繼續(xù)尋找,到Object.prototype中尋找,最后沒找到則會返回一個null。
很明顯,在這里實例animal中沒有changeName方法,所以需要到Animal.prototype尋找changeName方法,并調(diào)用成功修改了實例animal中的name屬性,為Tiger。
這個時候由于Cat.prototype是指向?qū)嵗齛nimal的,因此Cat.prototype中的name屬性也變?yōu)門iger。
console.log(cat.name) // Cat
最后,獲取cat.name,與查找方法同樣,也是先去實例中cat查找是否含有name屬性,在這里很明顯是存在的,因此直接結(jié)束尋找,此時cat.name = 'Cat'。
感謝各位的閱讀!關(guān)于“JS原型鏈的示例分析”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,讓大家可以學(xué)到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。