1. 程式人生 > >原型物件(prototype)

原型物件(prototype)

我們建立的每個函式都有一個prototype(原型)屬性,這個屬性是一個指標,指向一個物件,而這個物件的用途是包含可以由特定型別的所有例項共享的屬性和方法。即:通過呼叫建構函式而建立的那個物件例項的原型物件。

function Person(){};

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

var person1=new Person();
person1.sayName();//'Nicholas'

var person2=new Person();
person2.sayName();//'Nicholas'

alert(person1.sayName==person2.sayName);//true

理解原型物件

無論什麼時候,只要建立了一個新函式,就會根據一組特定的規則為該函式建立一個prototype屬性。這個屬性指向函式的原型物件。在預設情況下,所有原型物件都會自動獲得一個constructor(建構函式)屬性,這個屬性是一個指向prototype屬性的指標。當呼叫建構函式建立一個新例項後,該例項的內部將包含一個指標(內部屬性),指向建構函式的原型物件。ES5中,管這個指標叫[[Prototype]]。

雖然可以通過物件例項訪問儲存在原型中的值,但卻不能通過物件例項重寫原型中的值。如果在例項中添加了一個屬性,而該屬性與例項原型中的一個屬性同名,那我們就在例項中建立該屬性,該屬性就會遮蔽原型中的那個屬性。

function Person(){};

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

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

person1.name='Greg';

console.log(person1.name);//Gret
console.log(person2.name);//Nicholas

當為物件例項新增一個屬性時,這個屬性就會遮蔽原型物件中儲存的同名屬性;即新增這個屬性只會阻止我們訪問原型中的那個屬性,但不會修改那個屬性。即使將這個屬性設定為null,也只會在例項中設定這個屬性,而不會恢復其指向原型的連線。不過,使用delete操作符可以完全刪除例項屬性,從而能夠重新訪問原型中的屬性。

更簡單的原型語法:

可以將Person.prototype設定為等於一個以物件字面量形式建立的新物件

function Person(){}

Person.prototype={
	name:'Nicholas',
	age:29,
	job:'Software Enhineer',
	sayName:function(){
		console.log(this.name);
	}
};



這樣寫的話,Constructor屬性不再指向Person了。當建立一個函式時,就會同時建立它的prototype物件,這個物件也會自動獲得constructor屬性。而採用物件字面量語法則本質上重寫了預設的prototype物件,因此constructor屬性也就變成了新物件的constructor屬性(指向object建構函式),不再指向Person函式。

如果constructor的值很重要,可以再將其設定回適當的值

function Person(){}

Person.prototype={
	constructor:Person,
	name:'Nicholas',
	age:29,
	job:'Software Enhineer',
	sayName:function(){
		console.log(this.name);
	}
};

原型的動態性:

由於在原型中查詢值的過程是一次搜尋,因此我們對原型物件所做的任何修改都能夠立即從例項上反映出來。

var friend=new Person();
Person.prototype.sayHi=function(){
	alert('Hi');
};
friend.sayHi();//'Hi'

但如果重寫整個原型物件,情況就會不一樣。呼叫建構函式時會為例項新增一個指向最初原型的[[prototype]]指標,而把原型修改為另一個物件就等於切斷了建構函式與最初原型之間的聯絡。注意:例項中的指標僅指向原型,而不指向建構函式。

function Person(){};

var friend = new Person();
Person.prototype = {
	constructor:Person,
	name:'Nicholas',
	age:29,
	job:'Software Enhineer',
	sayName:function(){
		alert(this.name);
	}
};
friend.sayName();//error