“我們創建的每個函數都有一個prototype(原型)屬性,這個屬性是一個指針,指向一個對象,而這個對象的用途是包含可以由特定類型的所有實例共享的屬性和方法。”
--摘自人民郵電出版社出版的Nicholas C.Zakas著的《JavaScript高級程序設計》(第2版)
上面提到的對象,就是原型對象,它的用途是“包含可以由特定類型的所有實例共享的屬性和方法”。那麼怎麼才能訪問到它呢?按照上面的說法,每個函數都有一個prototype 指針,這個指針指向了它的原型對象,所以我們可以通過函數的prototype屬性來訪問函數的原型對象。
下面用程序來說明。
- function SuperType(){}
- document.write(SuperType.prototype);//[object Object]
可見函數SuperType的確存在一個prototype屬性,其的確是指向了一個對象。但這個對象真是原型對象嗎?怎麼證明?上面不是說原型對象的用途是“包含可以由特定類型的所有實例共享的屬性和方法”,既然如此,那我們就來看這個對象是不是真的有這個功能。
- function SuperType(){}
- SuperType.prototype.name = 'Sam';//在SuperType.prototype指向的對象上增加了name屬性
- //在SuperType.prototype指向的對象上增加了sayName方法
- SuperType.prototype.sayName = function() {
- document.write(this.name);
- };
- SuperType.prototype.setName = function(name) {
- SuperType.prototype.name = name;
- };
- var instance1 = new SuperType();
- var instance2 = new SuperType();
- instance1.sayName();//Sam
- instance2.sayName();//Sam
- instance1.setName('Luce');
- instance1.sayName();//Luce
- instance2.sayName();//Luce
當實例instance1調用setName()函數更改了SuperType.prototype.name的值後,instance2.sayName()也會輸出Luce,說明SuperType.prototype指向的對象的確是“包含了可以由特定類型(這裏是SuperType)的所有實例所共享的屬性和方法”,所以由此可以得出結論:
SuperType.prototype指向的就是SuperType的原型對象,也即是函數的prototype屬性指向了函數的原型對象。
下面用程序來說明構造函數、實例和原型對象三者之間的關係。
首先是構造函數與實例之間的關係,實例就是通過調用構造函數創立的:
- function SuperType(name){
- this.name = name;
- this.sayName = function(){
- document.write(this.name);
- }
- }
- var instance1 = new SuperType("Sam");
- instance1.sayName();//Sam
- var instance2 = new SuperType("Luce");
- instance2.sayName();//Luce
我們在構造函數裏面定義了一個name屬性和一個sayName()函數,當調用new SuperType()創建實例時,就會調用構造函數SuperType創建實例對象,同時爲實例對象增加一個name 屬性和一個sayName()方法(也即是把this換成了實例對象(如this.name換成了instance1.name),所以每個實例的name和sayName()方法都是獨立的,注意和在原型對象上定義的 區別,在原型對象上定義是共享的)。
構造函數與原型對象的關係。前面已經說過,構造函數中有一個prototype屬性,該屬性是一個指針,指向了它的原型對象,那原型對象呢?是不是在它裏面也存在一個指針,指向構造函數呢?答案是的確如此。原型對象中有一個constructor屬性,該屬性指向了構造函數:
- function SuperType(){}
- document.write(SuperType.prototype.constructor);//function SuperType(){}
- document.write(SuperType.prototype.constructor == SuperType);//true
打印SuperType.prototype.constructor,輸出的是構造函數的定義,而我們知道函數名只是一個引用,其指向函數所在的地址,所以通過SuperType.prototype.constructor和SuperType的比較,返回了true,所以SuperType.prototype.constructor和SuperType一樣都指向了SuperType()函數,在這裏即是指向了構造函數。
最後是實例與原型對象的關係。前面的例子可以看到(最開始),實例可以訪問到在原型對象上定義的屬性和方法,那麼我們就可以猜測,實例中肯定有一個指針指向了原型對象,的確如此,實例中有一個屬性__proto__(IE中沒有這個屬性,所以不要在IE下測試),該屬性指向了原型對象:
- function SuperType(){}
- var instance = new SuperType();
- document.write(instance.__proto__ == SuperType.prototype);//true
SuperType.prototype指向了SuperType的原型對象,而instance.__proto__和SuperType.prototype比較返回了true,這就說明instance.__proto__也指向了SuperType的原型 對象。
以上即是JavaScript原型對象的相關信息