DOM筆記(十二):又談原型對象

由於以前謝過一篇關於原型對象的筆記:淺談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

  1. <span style="font-size:14px;">function Person(){}  

  2.   

  3. //先建立一個實例  

  4. var per1 = new Person();  

  5.   

  6. //重寫原型  

  7. Person.prototype={  

  8. constructor:Person,  

  9. name:「dwqs」,  

  10. age:20,  

  11. sayName:function()  

  12. {  

  13. alert(this.name);  

  14. }  

  15. };  

  16. 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

 

原文首發:http://www.ido321.com/1372.html

相關文章
相關標籤/搜索