1. 程式人生 > >js高階建構函式,例項物件和原型物件——prototype、__proto__和constructor構造器

js高階建構函式,例項物件和原型物件——prototype、__proto__和constructor構造器

一、前言

  瞭解JavaScript面向物件,需要先了解三個名詞: 建構函式,例項物件和原型物件

  注意:JavaScript中沒有類(class)的概念,取而代之的是建構函式,兩者類似卻又有很大的差別。

  先上程式碼,最常用的:

function Person(name, age) {
 this.name = name;
 this.age = age;
 this.eat= function() { alert('吃西紅柿') } 
}
var person1 = new Person('小米', 28);
var person2 = new Person('大米', 23);

  Chrome列印測試,上圖:

上圖分別是:

  • 圖一列印perspn1例項物件,
  • 圖二列印Person建構函式,
  • 圖三列印建構函式的prototype(即Person的原型物件)和person1的__proto__

   

  通過上面的列印,我們可以發現幾個問題:

  1. 例項物件和建構函式一點也不像,
  2. person1.__proto__和Person.prototype一模一樣

  我們先來看看第一個問題:例項物件和它的建構函式——打印出來的內容一點也不像

   

  這個問題就大了呀!

   我們都知道,在java中,類和它的例項物件之間有很緊密的關係,你的(屬性和方法)是我的,我的還是我的!

  可是到了js這裡,Person建構函式中並沒有體現出他本該有的屬性和方法

  也就是說,無論我們例項化出來多少個person,他們的屬性和方法都是不一樣的。屬性不一樣還可以理解,方法不一樣就意味著:每個例項出來的person的方法並不是共用的(並不指向同一個地址空間),那我們要建構函式還有什麼意義?

  我們要的還是類和例項物件的關係那樣,能夠共享資料,節省記憶體空間

 

  這就引出了我們今天要講的關鍵:原型

 

二、正文

(一)、使用原型物件造共用屬性和方法

  前面已經講到,js的建構函式和例項物件之間,並不能夠實現共享資料,節省記憶體空間的作用,所以我們就引入了原型

這一概念

  再上程式碼:這次我們添加了原型方法play()

//建構函式
function Person(name, age) {
 this.name = name;
 this.age = age;
 this.eat= function() { alert('吃西紅柿') } 
}
//新增原型方法
Person.prototype.play = function() { alert("玩溜溜球")}
//例項化物件
var person1 = new Person('小米', 28);
var person2 = new Person('大米', 23);

  在僅限Chrome測試:

上圖分別是:

  • 圖一列印perspn1例項物件,
  • 圖二列印Person建構函式,
  • 圖三列印建構函式的prototype(即Person的原型物件)和person1的__proto__

  

  通過上圖可以知道:建構函式中定義的方法,例項化後並不一樣,而原型物件prototype中定義的方法確實相等的(指向同一地址)

  添加了原型方法後,例項物件person1和建構函式Person上並沒有直觀體現,反而在Person.prototype和person1.__proto__中顯示了出來

     由此,我們可以知道,JS中給同一建構函式的例項物件 新增共用屬性和方法,需要使用prototype這一屬性,也就是原型物件來實現

   

(二)、prototype和__proto__和constructor構造器

上圖表現出:Person.prototype === person1.__proto__

即:例項物件的__proto__和建構函式的prototype相等(指向同一地址),完全一樣

上圖,圖一列印Person.prototype;圖二列印person1.__proto__;圖三列印Person建構函式

通過上面三張圖,我們可以發現:Person.prototype.constructor和person1.__proto__.constructor以及Person一模一樣

 

上圖表現出:Person.prototype.constructor === Person

 即:建構函式的原型物件(prototype)的構造器(constructor)指向該建構函式

  

通過之前的列印和上圖,我們可以發現,

  • 例項物件中都有__proto__屬性,而建構函式中都有prototype屬性,
  • prototype和__proto__都有構造器constructor,其實例項物件的__proto__和建構函式的prototype是一樣的(Person.prototype === person1.__proto__
  • 建構函式的原型物件(prototype)的構造器(constructor)指向該建構函式(Person.prototype.constructor === Person

 

 (三)、使用原型的注意事項

  原型屬性和方法統一定義時,需要定義構造器constructor,即將建構函式的原型物件中的構造器指向該建構函式,否則原型屬性和方法定義失敗

//新增原型方法
Person.prototype.job= "程式設計師"
Person.prototype.address = "蘇州" 
Person.prototype.study= function() { alert("學JavaScript")}

//可以這樣定義嗎?
Person.prototype = {
    job:  "程式設計師",
    address: "蘇州" ,
    study:  function() { alert("學JavaScript")}
}

//上面的原型物件定義出錯,需要加上constructor--手動修改構造器的指向
Person.prototype = {
    constructor: Person
    job:  "程式設計師",
    address: "蘇州" ,
    study:  function() { alert("學JavaScript")}
}

  分別將兩種新增原型屬性和方法的方式列印看看:

上圖分別是:

  • 圖一為錯誤示範,表示未手動修改構造器指向,結果列印顯示Person.prototype丟失構造器constructor,被新新增的物件覆蓋
  • 圖二為正確示範,表示手動修改構造器指向,即加上constructor: Person,

   

 三、結束

  加油哦,最後來張圖