為了解決構造函數的對象執行個體之間無法共享屬性的缺點,js提供了prototype屬性。
js中每個資料類型都是對象(除了null和undefined),而每個對象都繼承自另外一個對象,後者稱為“原型”(prototype)對象,隻有null除外,它沒有自己的原型對象。
原型對象上的所有屬性和方法,都會被對象執行個體所共享。
通過構造函數生成對象執行個體時,會将對象執行個體的原型指向構造函數的prototype屬性。每一個構造函數都有一個prototype屬性,這個屬性就是對象執行個體的原型對象。
function
Person(name,height){
this
.name=name;
this
.height=height;
}
Person.prototype.hobby=
function
(){
return
'watching movies'
;
}
var
boy=
new
Person(
'keith'
,180);
var
girl=
new
Person(
'rascal'
,153);
console.log(boy.name);
//'keith'
console.log(girl.name);
//'rascal'
console.log(boy.hobby===girl.hobby);
//true
上面代碼中,如果将hobby方法放在原型對象上,那麼兩個執行個體對象都共享着同一個方法。我希望大家都能了解的是,對于構造函數來說,prototype是作為構造函數的屬性;對于對象執行個體來說,prototype是對象執行個體的原型對象。是以prototype即是屬性,又是對象。
原型對象的屬性不是對象執行個體的屬性。對象執行個體的屬性是繼承自構造函數定義的屬性,因為構造函數内部有一個this關鍵字來指向将要生成的對象執行個體。對象執行個體的屬性,其實就是構造函數内部定義的屬性。隻要修改原型對象上的屬性和方法,變動就會立刻展現在所有對象執行個體上。
Person.prototype.hobby=
function
(){
return
'swimming'
;
}
console.log(boy.hobby===girl.hobby);
//true
console.log(boy.hobby());
//'swimming'
console.log(girl.hobby());
//'swimming'
上面代碼中,當修改了原型對象的hobby方法之後,兩個對象執行個體都發生了變化。這是因為對象執行個體其實是沒有hobby方法,都是讀取原型對象的hobby方法。也就是說,當某個對象執行個體沒有該屬性和方法時,就會到原型對象上去查找。如果執行個體對象自身有某個屬性或方法,就不會去原型對象上查找。
boy.hobby=
function
(){
return
'play basketball'
;
}
console.log(boy.hobby());
//'play basketball'
console.log(girl.hobby());
//'swimming'
上面代碼中,boy對象執行個體的hobby方法修改時,就不會在繼承原型對象上的hobby方法了。不過girl仍然會繼承原型對象的方法。