由於以前謝過一篇關於原型對象的筆記:淺談JavaScript中的原型模式。如今我又從新看到這個話題,對原型有了進一步的理解,因此,又要談談原型對象。javascript
1、理解原型對象html
建立的每個函數都有一個prototype屬性,它指向這個函數的原型對象。利用原型模式建立的方法和屬性是被全部實例所共享的。java
function Person(){} Person.prototype.name="dwqs"; Person.prototype.age=20; Person.prototype.sayName=function() { alert(this.name); };var per1 = new Person(); per1.sayName(); //dwqsvar per2 = new Person(); per2.sayName(); //dwqsalert(per1.sayName == per2.sayName); //true
默認狀況下,prototype指向的原型對象自動獲取一個constructor屬性,指向prototype屬性所在的函數,而原型對象的其它方法和屬性均從Object繼承。web
當調用Person的構造函數建立對象per1和per2時,Person的每一個實例(per1和per2)均包含一個指向構造函數(Person)的原型對象的指針。ECMA-262第5版給指針取名爲[[Prototype]]。瀏覽器
因此,實例中的指針僅指向原型,而不指向構造函數。雖然沒有標準的方法直接訪問[[Prototype]]特性,但在DOM筆記(十一)中提供了hasOwnProperty()和isPropertyOf()方法來反應原型對象和實例之間的關係。函數
//isPrototypeOf(obj)檢測obj的[[prototype]]是否指向調用此方法的對象alert(Person.prototype.isPrototypeOf(per1)); //truealert(Person.prototype.isPrototypeOf(per2)); //true
hasOwnProperty()則是判斷屬性是存在原型中仍是實例中,只有存在實例中時,才返回true。this
per1.blog = "www.ido321.com"; alert(per1.hasOwnProperty("blog")); //truealert(Person.prototype.hasOwnProperty("blog")); //falsealert(per1.hasOwnProperty("name")); //falsealert(Person.prototype.hasOwnProperty("name")); //true
若實例屬性和原型屬性同名,則同名的原型屬性會被屏蔽,可是不會修改原型中的同名屬性,當刪除同名的實例屬性後,又能從新訪問被屏蔽的原型屬性。spa
per1.name="i94web"; alert(per1.name); //i94web,來自實例alert(per2.name); //dwqs 來自原型delete per1.name; alert(per1.name); //dwqs
ECMAScript 5提供了Object.getPrototypeOf(obj)來訪問obj的[[Prototype]]的指向,即返回obj的原型對象.net
alert(Object.getPrototypeOf(per1) == Person.prototype); //true alert(Object.getPrototypeOf(per1).name); //dwqs
2、__proto__屬性prototype
在IE十一、FireFox、Google等現代瀏覽器中,每一個對象支持__proto__(先後都是兩個下劃線)屬性用於訪問父類的原型對象。但要注意的是:
一、原型對象應用__proto__屬性時,返回當前類的父類的原型對象的引用;當實例對象應用__proto__屬性時,返回當前實例所屬類的原型對象的引用。
二、Object.prototype.__proto__返回null,Object沒有父類。
三、prototype是靜態屬性,__proto__是實例屬性。
//全是truealert(Array.prototype.__proto__ == Object.prototype); alert((new Array()).__proto__ == Array.prototype); alert(Person.prototype.__proto__ == Object.prototype); alert(per1.__proto__ == Person.prototype); alert(Object.prototype.__proto__ == null);
3、重寫原型
若是在原型上定義屬性或者方法,每次都要將Person.prototype敲一遍,很麻煩。一個簡單的方法就是重寫原型。
function Person(){} Person.prototype={ name:"dwqs", age:20, sayName:function() { alert(this.name); } }; var per1 = new Person(); alert(per1 instanceof Object); //truealert(per1 instanceof Person); //truealert(per1.constructor == Object); //truealert(per1.constructor == Person); //false
由於重寫了默認的prototype對象,因此constructor屬性指向了新對象的constructor屬性(Object構造函數),而不是指向Person了。若是constructor指向很重要,能夠從新定義:
function Person(){} Person.prototype={ constructor:Person, //從新定義constructor name:"dwqs", age:20, sayName:function() { alert(this.name); } }; var per1 = new Person(); alert(per1.constructor == Person); //true
這樣設置以後,constructor的特性[[Enumerable]]是true了(參考DOM筆記(十一)),便可以枚舉,默認狀況下,該屬性不可枚舉。
正如前文說的,實例中的指針僅指向原型,而不指向構造函數。因此重寫原型對象以後,會切斷現有原型和任何以前已經存在的對象實例之間的聯繫。
[javascript] view plaincopy
<span style="font-size:14px;">function Person(){}
//先建立一個實例
var per1 = new Person();
//重寫原型
Person.prototype={
constructor:Person,
name:「dwqs」,
age:20,
sayName:function()
{
alert(this.name);
}
};
per1.sayName(); //錯誤:Uncaught TypeError: undefined is not a function</span>
重寫原型對象以前是這樣的:
重寫原型對象變成這樣了:
4、原生對象的原型
全部原生引用類型,如Object、Array、String等都在其構造函數的原型上定義了方法。在Array.prototype上能夠找到sort(),在String.prototype上能夠找到substring
alert(typeof Array.prototype.sort); //functionalert(typeof String.prototype.substring); //function
所以,也能夠在原型對象上爲引用類型定義新的方法
String.prototype.startWith=function(str) { return this.indexOf(str) == 0; }var msg = "Hello world"; alert(msg.startWith("Hello")); //true