javaScript系列 [03]-javaScript原型對象

[03]-javaScript原型對象

引用: javaScript是一門基於原型的語言,它容許對象經過原型鏈引用另外一個對象來構建對象中的複雜性,JavaScript使用原型鏈這種機制來實現動態代理。當試圖去引用某一個屬性時,它會遍歷整個原型鏈,直到最後的節點。JavaScript專家編程·P24java

1.1 原型對象說明

在JavaScript中除了基本數據類型外的其它數據都是對象類型,包括對象、函數、數組等,它們跟原型對象密不可分。編程

JavaScript語言中有一個很是重要的概念,叫作原型對象,理解原型對象是進一步理解這門語言的基礎,由於它是一門基於原型的語言,也由於全部的代碼幾乎都和原型對象有關,接下來咱們先了解下原型對象是什麼。數組

原型對象瀏覽器

在上一篇文章JavaScript系列 [02]-javaScript對象探析中,咱們介紹了使用自定義構造函數建立對象的方式,在構造函數被建立出來的時候,系統會默認幫構造函數建立並關聯一個Object類型的新對象,咱們稱該對象就是這個構造函數的原型對象,構造函數的原型對象默認是一個空對象。函數

1.2 原型對象的性質

構造函數相關聯的原型對象的成員(屬性和方法),能夠被使用該構造函數建立出來的對象訪問,即以自定義構造函數方式建立出來的全部實例對象,都自動擁有和共享該構造函數原型對象中的全部屬性和方法(想想爲何空對象可使用toString方法,全部的數組均可以使用push等方法)。post

代碼示例this

 1  //01 聲明構造函數Person
 2 function Person(name) {
 3     this.name = name;
 4 }
 5 //02 打印構造函數相關聯的原型對象
 6 console.log(Person.prototype);  //Objec類型的空對象
 7 //03 給構造函數原型對象添加方法
 8 Person.prototype.showName = function () {
 9     console.log(this.name);
10 };
11 //04 使用構造函數建立實例對象
12 var p = new Person("文頂頂");
13 p.showName();       //文頂頂
14 console.log(p);

代碼說明spa

☞ 上面的代碼先提供了Person構造函數,該函數聲明後,咱們經過Person.prototype訪問其原型對象打印獲得一個Object類型的空對象,說明全部的構造函數建立後默認擁有prototype屬性,即構造函數默認有一個相關聯的原型對象(Object類型空對象)。prototype

☞ 隨後咱們經過對象的動態特性給Person的原型對象添加了showName方法,經過打印結果能夠驗證構造函數的實例化對象(p)能夠訪問其原型對象上面的成員。代理

經過對代碼和其運行結果分析,咱們不可貴出構造函數(Person)、原型對象(Person.prototype)、實例對象(p)之間的關係圖,以下。

代碼說明

① 實例對象p由Person構造函數實例化而來。

② Person構造函數能夠經過prototype屬性訪問其原型對象。

③ 實例對象p能夠經過proto屬性訪問其構造函數的原型對象(能夠簡稱爲p的原型對象,咱們在說原型對象的時候,應該先肯定主語是構造函數仍是實例對象,若是主語是構造函數,那麼指的是構造函數.prototype,若是主語是實例對象,那麼指的是建立該實例對象的構造函數相關聯的原型對象,表示爲實例對象.proto)。

④ 原型對象(Person.prototype)能夠經過constructor(構造器)屬性來訪問其關聯的構造函數,沒法訪問實例對象。

下面貼出上面代碼更詳細的原型結構關係圖。

原型對象的訪問

1  //獲取原型對象的方式
2 //01 構造函數訪問原型對象:構造函數.prototype
3 console.log(Person.prototype);
4 //02 構造函數的實例對象訪問原型對象:實例對象.__proto__
5 console.log(p.__proto__);
6 console.log(p.__proto__ == Person.prototype);
7 //03 經過Object.getPrototypeOf方法傳遞實例對象做爲參數訪問
8 console.log(Object.getPrototypeOf(p));

總結一下,原型對象的訪問方式以下

① 構造函數.prototype
② 實例對象.__proto__
③ Object.getPrototypeOf(實例對象)

原型對象總結

❐ 全部的對象都擁有__proto__屬性,函數既擁有prototype屬性又擁有__proto__屬性。
❐ 對象的__proto__屬性指向其構造函數相關聯的原型對象(函數的__proto__屬性也同樣,指向其構造函數Function相關的原型對象,是一個空函數)。
❐ 函數的prototype屬性指向默認相關聯的原型對象(函數和構造函數本質無差異)。

__proto__是一個非標準屬性,即ECMAScript中並不包含該屬性,這只是某些瀏覽器爲了方便開發人員開發和調試而提供的一個屬性,不具有通用性。建議在調試的時候可使用該屬性,但不能出如今正式的代碼中,開發中可使用Object.getPrototypeOf方法來替代。

 

1.3 設置原型對象

所謂設置原型對象就是給構造函數的原型對象添加成員(屬性和方法),具體的方式有兩種

① 利用對象的動態特性設置
② 替換原有的原型對象

代碼示例

 1  //01 聲明構造函數Person
 2 function Person(name,age) {
 3     this.name = name;
 4     this.age = age || 18;
 5 }
 6 //02 給構造函數原型對象添加方法
 7 //設置原型對象的第一種方法
 8 Person.prototype.showName = function () {
 9     console.log("姓名 "+this.name);
10 };
11 Person.prototype.showAge = function () {
12     console.log("年齡 "+this.age);
13 };
14 //04 使用構造函數建立實例對象
15 var p1 = new Person("文頂頂");
16 p1.showName();       //姓名 文頂頂
17 p1.showAge();        //年齡 18
18 var p2 = new Person("章飛一絕",99);
19 p2.showName();       //姓名 章飛一絕
20 p2.showAge();        //年齡 99

像上面代碼這樣直接利用對象的動態特性來設置原型對象,在原有原型對象的基礎上添加屬性和方法很是簡單,可是若是要添加的方法或屬性比較多,那麼冗餘代碼會比較多,這種狀況推薦直接替換原有的原型對象。

 1  //01 聲明構造函數Person
 2 function Person(name,age) {
 3     this.name = name;
 4     this.age = age || 18;
 5 }
 6 //02 給構造函數原型對象添加方法
 7 //設置原型對象的第二種方法:直接替換原先的原型對象
 8 Person.prototype = {
 9     constructor:Person,
10     showName:function () {
11         console.log("姓名 "+this.name);
12     },
13     showAge:function () {
14         console.log("年齡 "+this.age);
15     }
16 };
17 //04 使用構造函數建立實例對象
18 var p = new Person("文頂頂");
19 p.showName();       //姓名 文頂頂
20 p.showAge();        //年齡 18
21 console.log(p.constructor); //Person函數

注意 若是是直接替換原型對象,那麼須要修正構造器屬性,讓constructor指向構造函數。
說明 由於替換的時候實際上是用字面量的方式從新建立了新的對象,該對象做爲Object構造函數的原型對象,內部沒有constructor屬性。這個時候若是要經過實例對象(好比p)的構造器屬性判斷其類型,那麼會先在p身上找,沒有則查找原型對象發現也沒有,最終獲得的Object.prototype身上的構造器屬性,結果爲Object 。


相關文章
相關標籤/搜索