JavaScrip原型理解(一)

示意圖

基本概念

每個(gè)函數(shù)都有一個(gè)prototype(原型)屬性,這個(gè)屬性是一個(gè)指針,指向一個(gè)對(duì)象;而這個(gè)對(duì)象的用途是包含可以由特定類型的所有實(shí)例共享的屬性和方法。那么prototype就是通過調(diào)用構(gòu)造函數(shù)而創(chuàng)建的那個(gè)對(duì)象實(shí)例的原型對(duì)象。使用原型對(duì)象的好處是可以讓所有對(duì)象實(shí)例共享它所包含的屬性和方法。換句話說,不必在構(gòu)造函數(shù)中定義對(duì)象實(shí)例的信息,而是可以將這些信息直接添加到原型對(duì)象中,如下面的例子所示。

function Person(){
}
Person.prototype.name = 'hello word';
Person.prototype.age = 4;
Person.prototype.say = function(){
console.log(this.name);
}
var person1 = new Person();
person1.say();// hello word

var person2 = new Person();
person2.say();// hello word

console.log(person1.say == person2.say) //true

以上代碼直接把所有屬性和方法直接添加到了Person的prototype屬性中,構(gòu)造函數(shù)變成了空函數(shù),我們?nèi)钥梢酝ㄟ^調(diào)用構(gòu)造函數(shù)來創(chuàng)建對(duì)象。而構(gòu)建的所有新對(duì)象都具有相同的屬性和方法,如上例person1和person2訪問都是同一組屬性和方法。

理解原型

無論什么時(shí)候,只要?jiǎng)?chuàng)建一個(gè)新函數(shù),就會(huì)為該函數(shù)創(chuàng)建一個(gè)prototype屬性,這個(gè)屬性指向函數(shù)的原型對(duì)象,默認(rèn)情況下,所有原型對(duì)象都會(huì)自動(dòng)獲取一個(gè)constructor(構(gòu)造函數(shù))屬性。這個(gè)屬性是一個(gè)指向prototype屬性所在函數(shù)的指針,如上例Person.prototype.constructor指向的是Person。而通過這個(gè)構(gòu)造函數(shù),我們還可繼續(xù)為原型對(duì)象添加其他屬性和方法。

創(chuàng)建了自定義的構(gòu)造函數(shù)之后,其原型對(duì)象默認(rèn)只會(huì)取得constructor屬性;至于其他方法,則都是從Object繼承而來的。當(dāng)調(diào)用構(gòu)造函數(shù)創(chuàng)建一個(gè)新實(shí)例后,該實(shí)例的內(nèi)部將包含一個(gè)指針(內(nèi)部屬性),指向構(gòu)造函數(shù)的原型對(duì)象。ECMA-262第5版中管這個(gè)指針叫[[Prototype]]。

如上代碼

圖展示了Person構(gòu)造函數(shù)、Person的原型屬性以及Person現(xiàn)有的兩個(gè)實(shí)例之間的關(guān)系。在此,Person.prototype指向了原型對(duì)象,而Person.prototype.constructor又指回了Person。原型對(duì)象中除了包含constructor屬性之外,還包括后來添加的其他屬性。Person的每個(gè)實(shí)例——person1和person2都包含一個(gè)內(nèi)部屬性,該屬性僅僅指向了Person.prototype;換句話說,它們與構(gòu)造函數(shù)沒有直接的關(guān)系。此外,要格外注意的是,雖然這兩個(gè)實(shí)例都不包含屬性和方法,但我們卻可以調(diào)用person1.sayName()。這是通過查找對(duì)象屬性的過程來實(shí)現(xiàn)的。

每當(dāng)代碼讀取某個(gè)對(duì)象的某個(gè)屬性時(shí),都會(huì)執(zhí)行一次搜索,目標(biāo)是具有給定名字的屬性。搜索首先從對(duì)象實(shí)例本身開始。如果在實(shí)例中找到了具有給定名字的屬性,則返回該屬性的值;如果沒有找到,則繼續(xù)搜索指針指向的原型對(duì)象,在原型對(duì)象中查找具有給定名字的屬性。如果在原型對(duì)象中找到了這個(gè)屬性,則返回該屬性的值。也就是說,在我們調(diào)用person1.say()的時(shí)候,會(huì)先后執(zhí)行兩次搜索。首先,解析器會(huì)問:“實(shí)例person1有say屬性嗎?”答:“沒有?!比缓?,它繼續(xù)搜索,再問:“person1的原型有say屬性嗎?”答:“有?!庇谑?,它就讀取那個(gè)保存在原型對(duì)象中的函數(shù)。當(dāng)我們調(diào)用person2.say()時(shí),將會(huì)重現(xiàn)相同的搜索過程,得到相同的結(jié)果。而這正是多個(gè)對(duì)象實(shí)例共享原型所保存的屬性和方法的基本原理。

function Person(){
}

Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.say = function(){
    alert(this.name);
};

var person1 = new Person();
var person2 = new Person();

person1.name = "Greg";
alert(person1.name);     //"Greg"——來自實(shí)例
alert(person2.name);     //"Nicholas"——來自原型

雖然可以通過對(duì)象實(shí)例訪問保存在原型中的值,但卻不能通過對(duì)象實(shí)例重寫原型中的值。如果我們?cè)趯?shí)例中添加了一個(gè)屬性,而該屬性與實(shí)例原型中的一個(gè)屬性同名,那我們就在實(shí)例中創(chuàng)建該屬性,該屬性將會(huì)屏蔽原型中的那個(gè)屬性。來看下面的例子。

注:使用hasOwnProperty()方法可以檢測(cè)一個(gè)屬性是存在于實(shí)例中,還是存在于原型中。這個(gè)方法(不要忘了它是從Object繼承來的)只在給定屬性存在于對(duì)象實(shí)例中時(shí),才會(huì)返回true。

更簡(jiǎn)單的原型語(yǔ)法

function Person(){
}

Person.prototype = {
    name : "Nicholas",
    age : 29,
    job: "Software Engineer",
    say : function () {
        alert(this.name);
    }
};

在上面的代碼中,我們將Person.prototype設(shè)置為等于一個(gè)以對(duì)象字面量形式創(chuàng)建的新對(duì)象。最終結(jié)果相同,但有一個(gè)例外:constructor屬性不再指向Person了。前面曾經(jīng)介紹過,每創(chuàng)建一個(gè)函數(shù),就會(huì)同時(shí)創(chuàng)建它的prototype對(duì)象,這個(gè)對(duì)象也會(huì)自動(dòng)獲得constructor屬性。而我們?cè)谶@里使用的語(yǔ)法,本質(zhì)上完全重寫了默認(rèn)的prototype對(duì)象,因此constructor屬性也就變成了新對(duì)象的constructor屬性(指向Object構(gòu)造函數(shù)),不再指向Person函數(shù)。此時(shí),盡管instanceof操作符還能返回正確的結(jié)果,但通過constructor已經(jīng)無法確定對(duì)象的類型了

function Person(){
}

Person.prototype = {
    constructor : Person,
    name : "Nicholas",
    age : 29,
    job: "Software Engineer",
    say : function () {
        alert(this.name);
    }
};

在此,用instanceof操作符測(cè)試Object和Person仍然返回true,但constructor屬性則等于Object而不等于Person了。如果constructor的值真的很重要,可以像下面這樣特意將它設(shè)置回適當(dāng)?shù)闹怠?/p>

JavaScript高級(jí)程序設(shè)計(jì)(第3版)讀書筆記
GitHub:JavaScript-Demo

最后編輯于
?著作權(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)容