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,

   

 三、結束

  加油哦,最后來張圖

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM