理解js的 prototype原型物件

武文博KevinLM發表於2018-04-22

在我看過的關於原型的文章中,這篇是說的最好的!各位盡情享用

我們建立的每個函式都有一個prototype(原型)屬性,這個屬性是一個指標,指向一個物件,而這個物件的用途是包含可以由特定型別的所有例項共享的屬性和方法。如果按照字面意思來理解,那麼prototype就是通過呼叫建構函式而建立的那個物件例項的原型物件。使用原受物件的好處是可以讓所有物件例項共享它所包含的屬性和方法。換句話說,不必在建構函式中定義物件例項的資訊,而是可以將這些資訊直接新增到原型物件中,如下面的例子所示。

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function Person(){}
Person.prototype.name = 'mychirs';
Person.prototype.age = 29;
Person.prototype.job = 'Software Engineer';
Person.prototype.sayName = function(){
  alert(this.name);
};
 
var person1 = new Person();
person1.sayName();//'mychirs'
 
var person2 = new Person();
person2.sayName();//'mychirs'
 
alert(person1.sayName == person2.sayName);//true

 

 

在此,我們將sayName()方法和所有屬性直接新增到了Person的prototype屬性中,建構函式變成了空函式。即使如此,也仍然可以通過呼叫建構函式來建立新物件,而且新物件還會具有相同的屬性和方法。但與建構函式模式不同的是,新物件的這些屬性和方法是由所有例項共享的。換句話說.personl和person2訪問的都是同一組屬性和同一個sayName()函式。要理解原型模式的T作原理,必須先理解ECMAScript巾原型物件的性質。

 

理解原型物件


無論什麼時候,只要建立了一個新函式,就會根據一組特定的規則為該函式建立一個prototype屬性,這個屬性指向函式的原型物件。在預設情況下,所有原型物件都會自動獲得一個constructor(建構函式)屬性,這個屬性包含一個指向prot otype屬性所在函式的指標。就拿前面的例子來說,Person.prototype. constructor措向Person。而通過這個建構函式,我們還可繼續為原型物件新增其他屬性和方法。
建立了自定義的建構函式之後,其原型物件預設只會取得constructor屬性;至於其他方法,則都是從Obj ect繼承而來的。當呼叫建構函式建立一個新例項後,該例項的內部將包含—個指標(內部屬性),指向建構函式的原型物件。ECMA-262第5版中管這個指標叫[[Prototype】]。雖然在指令碼中沒有標準的方式訪問【[ Prototype]],但Firefox、Safari和Chrome在每個物件上都支援一個屬性—proto_;而在其他實現中,這個屬性對指令碼則是完全不可見的。不過,要明確的真正重要的一點就是,這個連線存在於例項與建構函式的原型物件之間,而不是存在於例項與建構函式之間。
以前面使用Person建構函式和Person.prototype建立例項的程式碼為例,圖6-1展示了各個物件之間的關係。

\

 

 

 

上圖展示rr Person建構函式、Person的原型屬性以及Person現有的兩個例項之間的關係。在此,Person *prototype指向了原型物件,而Person.prototype.constructor叉指回了Person。原型物件中除了包含cons t,ruct or屬性之外,還包括後來新增的其他屬性。Person的每個例項personl和person2都包含一個內部屬性,該屬性僅僅指向了Person.prot otype;換句話說,它們與建構函式沒有直接的關係。此外,要格外注意的是,雖然這兩個例項都不包含屬性和方法,但我們卻載入中...可以呼叫personl.sayName()。這是通過查詢物件屬性的過程來實現的。
雖然在所有實現中都無法訪問到[[Prototype]:,但可以通過isProcotypeOf()方法來確定物件之間是否存在這種關係。從本質上講,如果[[ Prototype]]指向呼叫isPrototypeOf()方法的物件[Person.prototype).那麼這個方法就返回true,如下所示:

 

 
1
2
alert(Person.prototype.isPrototypeOf(personl)); //true
alert(Person.prototype.isPrototypeOf(person2)); //true


這裡,我們用原型物件的isPrototypeOf()方法測試了personl和person2 0因為它們內部都有一個指向Person.prototype的指標,因此都返回了true。

 

ECMAScript 5增加了一個新方法,叫Object.getPrototypeOf(),在所有支援的實現中,這個方法返回[[PrototypeJ]]的值。例如:

 

1
2
alert(Object.get PrototypeOf(personl) == Person.prototype); //true
alert(Object.get PrototypeOf(personl).name );   //'Nicholas'

 

 

這裡的第一行程式碼只是確定Object.getPrototypeOf()返回的物件實際就是這個物件的原型。第二行程式碼取得了原型物件中name屬性的值,也就是'Nicholas'。使用Object.getPrototypeOf()可以方便地取得一個物件的原型,而這在利用原型實現繼承(本章稍後會討論)的情況下是非常重要的。支援這個方法的瀏覽器有IE9+、Firefox 3.5+、Safari 5+、Opera 12+和Chrome。

每當程式碼讀取某個物件的某個屬性時,都會執行一次搜尋,目標是具有給定名字的屬性。搜尋首先從物件例項本身開始。如果在例項中找到了具有給定名字的屬性,則返回該屬性的值;如果沒有找到,則繼續搜尋指標指向的原型物件,在原型物件中查詢具有給定名字的屬性。如果在原型物件中找到了這個屬性,則返回該屬性的值。也就是說,在我們呼叫personl. sayName《)的時候,會先後執行兩次搜尋。首先,解析器會同:“例項personl有sayName屬性嗎?”答:“沒有。”然後,它繼續搜尋,再問:“personl的原捌有sayName屬性嗎?”答:“有。”於是,它就讀取那個儲存在原型物件中的函式。當我們呼叫person2.sayName()時,將會重現相同的搜尋過程,得到相同的結果。而這正是多個物件例項共享原型所儲存的屬性和方法的基本原理。


轉自 :http://www.cnblogs.com/mfc-itblog/p/5736785.html

相關文章