理解JavaScript中的原型

學習JavaScript有一段時間了,感覺原型那塊兒又有點混亂了,現在寫個筆記整理一下思路。

什麼是原型

每創建一個函數,這個函數都會自帶一個屬性prototype指向一個原型對象,最初這個原型對象只包含一個屬性constructor,這是指向我們創建的那個函數的指針。也就是說函數和原型對象分別通過prototype和constructor這兩個屬性(指針)能找到對方。

我們可以通過fn.prototype.propertyName=value來給原型對象繼續添加屬性和方法。這些屬性和方法區別於在函數中書寫的實例屬性和方法。爲什麼會有這種區別或者說這種區別是怎麼做到的呢?來看看創建一個實例後發生了什麼。以下面的代碼來說明:

function Person(name,age){
    this.name=name,
    this.age=age;
}
Person.prototype.hobby = ["running","swimming","tennis"];
Person.prototype.country="China";
Person.prototype.showName=function(){alert(this.name);};

var person1 = new Person("anna",10);

這裏創建了一個實例person1,我們知道通過new方法創建的實例,原來Person中的this會被新創建的實例即person1取代,也就是說通過這樣的方式,我們爲對象person1增加了屬性name和age,這些是person1自己所擁有的屬性,獨立於其他Person的實例,叫做實例屬性。
同時,每創建一個實例,這個實例會自帶一個內部屬性[prototype],它是一個指向構造函數的原型對象的引用。也就是說person1對象其實現在包括了這麼三個屬性:

person1={
   _proto_:Person.prototype,
   name:"anna",
   age:10
}

這個內部屬性_proto_一般來說是不可以通過腳本來訪問到的,那它有什麼用呢?在進行屬性標識符查找的時候會用到它。
引擎在讀到某個對象的屬性時,會首先查找實例屬性中有沒有這個屬性,如果有則停止,沒有則通過內部屬性_proto_找到其關聯的原型對象,看原型對象中有沒有相應的屬性。

實例屬性和原型屬性同名

這裏需要注意,如果我們又爲實例添加了一個和原型對象中同名的屬性,或者說我們“重寫”原型中的屬性會發生什麼。這得分屬性是原始值類型還是引用類型。

  • 原始類型

    同名的實例屬性會屏蔽掉原型對象中的同名屬性,這裏的屏蔽的意思是,這個屬性是添加到實例屬性上的,跟原型對象中的屬性半毛錢關係沒有,按照查找標識符的順序會首先找到該實例屬性,就不會再往上找原型中的了。它根本就不會“重寫”原型對象中的屬性,根本就是兩個值,在內存中有兩個空間。通過hasOwnProperty()可以看到已經成爲自己的實例屬性了:

person1.country="USA";  //重寫屬性
alert(person1.hasOwnProperty("country"));//true

可通過delete person1.country來刪除實例屬性,這樣就又可以訪問到原型對象中的屬性了。

  • 引用類型

    引用類型也是一樣的,當實例屬性和原型中的屬性同名的時候,就會屏蔽原型中的屬性,可以通過delete(impletation.property)來刪除實例屬性以重新獲取原型中的屬性:

person1.hobby=['table tennis','singing'];
alert(person1.hasOwnProperty('hobby'));  //true

問題:原型對象showName方法中的this是實例對象?解釋爲誰調用this就是誰?
做了實驗,的確是原型對象方法中的this是指向實例對象的:

Person.prototype.name = 'lily';
var p = new Person('anna', 10);
p.showName();  // 顯示 anna

但如果實例沒有自己的屬性name,那麼會沿着原型鏈查找這個屬性,此時就是顯示原型對象上的屬性lily了。
由於時間關係先寫到這兒,後面還會有補充。。。。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章