標籤:
一、原型的概述:
我們建立的每個函數都有一個 prototype(原型)屬性,這個屬性是一個對象,它的用途是包含可以由特定類型的所有執行個體共用的屬性和方法。
邏輯上可以這麼理解:prototype 通過調用建構函式而建立的那個對象的原型對象。
使用原型的好處可以讓所有對象執行個體共用它所包含的屬性和方法。也就是說,不必在建構函式中定義對象資訊,而是可以直接將這些資訊添加到原型中。
二、使用原型建立對象
function Box() {} //聲明一個建構函式,函數體內什麼都沒有,如果有叫做執行個體屬性,執行個體方法 Box.prototype.name = ‘Lee‘; //在原型裡添加屬性 Box.prototype.age = 100; Box.prototype.run = function () { //在原型裡添加方法 return this.name + this.age + ‘運行中...‘; }; /*比較一下原型內的方法地址是否一致:*/ var box1 = new Box(); var box2 = new Box(); alert(box1.run == box2.run); //true,方法的引用地址保持一致
為了更進一步瞭解建構函式的聲明方式和原型模式的聲明方式,我們通過圖示來瞭解一下:
在原型模式聲明中,多了兩個屬性,這兩個屬性都是建立對象時自動產生的。
__proto__屬性是執行個體指向原型對象的一個指標,它的作用就是指向建構函式的原型屬性 constructor。通過這兩個屬性,就可以訪問到原型裡的屬性和方法了。
IE 瀏覽器在指令碼訪問__proto__會不能識別,Firefox和Google瀏覽器及其他某些瀏覽器均能識別。雖然可以輸出,但無法擷取內部資訊。
function Box() {} //聲明一個建構函式 Box.prototype.name = ‘Lee‘; //在原型裡添加屬性 Box.prototype.age = 100; Box.prototype.run = function () { //在原型裡添加方法 return this.name + this.age + ‘運行中...‘; }; var box1 = new Box(); var box2 = new Box(); alert(box1.prototype);//這個屬性是一個對象,訪問不到 alert(box1.__proto__); //這個屬性是一個指標指向prototype原型對象, 列印結果是[object Object] 在IE中結果是undefined /* constructor是建構函式的屬性,擷取建構函式本身 作用是被原型指標定位,然後等到建構函式本身,其實就是對象執行個體對應的原型對象 */ alert(box1.constructor); alert(box1.age);//可以直接存取原型對象中的屬性和方法,因為底層會自動調用prototype和__proto__和constructor等屬性
判斷一個對象是否指向了該建構函式的原型對象(即判斷一個對象執行個體是不是指向了對象的原型對象)可以使用 isPrototypeOf()方法來測試。
function Box() {} //聲明一個建構函式 Box.prototype.name = ‘Lee‘; //在原型裡添加屬性 Box.prototype.age = 100; Box.prototype.run = function () { //在原型裡添加方法 return this.name + this.age + ‘運行中...‘; }; var box1 = new Box(); var box2 = new Box(); alert(box1.age);//結果列印出age的值 alert(Box.prototype.isPrototypeOf(box1)); //只要執行個體化對象,即都會指向
三、原型模式的執行流程
1、先尋找建構函式執行個體裡的屬性或方法,如果有,立刻返回;
2、如果建構函式執行個體裡沒有,則去它的原型對象裡找,如果有,就返回;
雖然我們可以通過對象執行個體訪問儲存在原型中的值,但卻不能通過對象執行個體重寫原型中的值。
function Box() {} //聲明一個建構函式 Box.prototype.name = ‘Lee‘; //在原型裡添加屬性 Box.prototype.age = 100; Box.prototype.run = function () { //在原型裡添加方法 return this.name + this.age + ‘運行中...‘; }; var box1 = new Box(); alert(box1.name); //Lee,原型裡的值 box1.name = ‘Jack‘; alert(box1.name); //Jack,就近原則, var box2 = new Box(); alert(box2.name); //Lee,原型裡的值,沒有被 box1 修改
如果想要 box1 也能在後面繼續訪問到原型裡的值,可以把建構函式裡的屬性刪除即可,具體如下:
function Box() {} //聲明一個建構函式 Box.prototype.name = ‘Lee‘; //在原型裡添加屬性 Box.prototype.age = 100; Box.prototype.run = function () { //在原型裡添加方法 return this.name + this.age + ‘運行中...‘; }; var box1 = new Box(); alert(box1.name); //Lee,原型裡的值 box1.name = ‘Jack‘; alert(box1.name); //Jack,就近原則, delete box1.name; //刪除執行個體中屬性 alert(box1.name); Box.prototype.name = ‘kkk‘//覆蓋原型中name屬性的值 alert(box1.name);//結果是kkk delete Box.prototype.name;//刪除原型中的屬性值,之後結果是undefined alert(box1.name);
如何判斷屬性是在建構函式的執行個體裡,還是在原型裡?可以使用 hasOwnProperty()函數來驗證:
function Box() {} //聲明一個建構函式 Box.prototype.name = ‘Lee‘; //在原型裡添加屬性 Box.prototype.age = 100; Box.prototype.run = function () { //在原型裡添加方法 return this.name + this.age + ‘運行中...‘; }; var box1 = new Box(); alert(box1.name); //Lee,原型裡的值 box1.name = ‘Jack‘; alert(box1.name); //Jack,就近原則, alert(box1.hasOwnProperty(‘name‘)); //判斷執行個體是否存在指定屬性 執行個體裡有返回 true,否則返回 false
in操作符會在通過對象能夠訪問給定屬性時返回 true,無論該屬性存在於執行個體中還是原型中。
function Box() {} //聲明一個建構函式 Box.prototype.name = ‘Lee‘; //在原型裡添加屬性 Box.prototype.age = 100; Box.prototype.run = function () { //在原型裡添加方法 return this.name + this.age + ‘運行中...‘; }; var box1 = new Box(); alert(‘name‘ in box1); //true,存在執行個體中或原型
我們可以通過hasOwnProperty() 方法檢測屬性是否存在執行個體中,也可以通過 in 來判斷執行個體或原型中是否存在屬性。那麼結合這兩種方法,可以判斷原型中是否存在屬性。
function Box() {} //聲明一個建構函式 Box.prototype.name = ‘Lee‘; //在原型裡添加屬性 Box.prototype.age = 100; Box.prototype.run = function () { //在原型裡添加方法 return this.name + this.age + ‘運行中...‘; }; var box1 = new Box(); alert(box1.hasOwnProperty(‘name‘)); alert(‘name‘ in box1); //如果第一個為false說明執行個體中沒有該屬性,而第二個為true說明屬性存在原型中 //如果第一個為true,說明屬性存在執行個體中
也可以定義一個函數來判段,原理是一樣的
function Box() {} //聲明一個建構函式 Box.prototype.name = ‘Lee‘; //在原型裡添加屬性 Box.prototype.age = 100; Box.prototype.run = function () { //在原型裡添加方法 return this.name + this.age + ‘運行中...‘; }; function isProperty(object, property) { //判斷原型中是否存在屬性 return !object.hasOwnProperty(property) && (property in object); } var box1 = new Box(); alert(isProperty(box1, ‘name‘)) //true,如果原型有
JavaScript的原型基礎1