js 原型 _proto_, prototype, contructor的聯繫

困擾了本人很久的原型,很讓人頭疼,苦心鑽研後,總結以下:javascript

下面理解下:java

須要記住幾點: 記住!!!記住!!!記住!!!(重要的說3遍)函數

1. 實例的_proto_屬性指向構造函數的原型this

2. Function的構造函數是它本身spa

3._proto_和contructor屬性是對象所獨有的prototype

4.prototype屬性是函數所獨有的,由於函數也是一種對象,因此函數也擁有_proto_和contructor屬性設計

 

如今正式開始!讓咱們從以下一個簡單的例子展開討論,並配以相關的圖幫助理解:指針

function Foo() {...};code

let f1 = new Foo();orm

以上代碼表示建立一個構造函數Foo(),並用new關鍵字實例化該構造函數獲得一個實例化對象f1。雖然是簡簡單單的兩行代碼,然而它們背後的關係倒是錯綜複雜的,以下圖所示: 

 

 重要的有兩點:

1、 建立一個function的過程

Javascript 語言中,constructor 屬性是專門爲 function 而設計的,它存在於每個 function prototype 屬性中。這個 constructor 保存了指向 function 的一個引用。

在定義一個函數(代碼以下所示)時,

 

function F() {

// some code

}

 JavaScript 內部會執行以下幾個動做:

 

  1. 爲該函數添加一個原形(即 prototype)屬性
  2. prototype 對象額外添加一個 constructor 屬性,而且該屬性保存指向函數F 的一個引用

 

     

這樣當咱們把函數 F 做爲自定義構造函數來建立對象的時候,對象實例內部會自動保存一個指向其構造函數(這裏就是咱們的自定義構造函數 F)的 prototype 對象的一個屬性proto

 

因此咱們在每個對象實例中就能夠訪問構造函數的 prototype 全部擁有的所有屬性和方法,就好像它們是實例本身的同樣。固然該實例也有一個 constructor屬性了(從 prototype 那裏得到的),每個對象實例均可以經過 construtor 對象訪問它的構造函數

     

 2、new的理解

按照《悟透javascript》書中說的,new形式建立對象的過程實際上能夠分爲三步: 
第一步是創建一個新對象(叫A吧);

第二步將該對象(A)內置的原型對象設置爲構造函數(就是Person)prototype 屬性引用的那個原型對象;

第三步就是將該對象(A)做爲this 參數調用構造函數(就是Person),完成成員設置等初始化工做。

其中第二步中出現了一個新名詞就是內置的原型對象,注意這個新名詞跟prototype對象不是一回事,爲了區別我叫它inobj,inobj就指向了函數Personprototype對象。在personprototype對象中出現的任何屬性或者函數均可以在one對象中直接使用,這個就是javascript中的原型繼承了。

又頭暈了,上圖吧!

這樣one對象經過內置的原型對象inobj就能夠直接訪問Personprototype對象中的任何屬性與方法了。這也就解釋了上面的代碼中爲何one能夠訪問form函數了。由於prototype對象中有一個constructor屬性,那麼one也能夠直接訪問constructor屬性。

 

new操做符具體幹了什麼呢?其實很簡單,就幹了三件事情。

 

 var obj  = {};

 

obj.__proto__ = Base.prototype;

 

Base.call(obj);

 

第一行,咱們建立了一個空對象obj
第二行,咱們將這個空對象的__proto__成員指向了Base函數對象prototype成員對象
第三行,咱們將Base函數對象的this指針替換成obj,而後再調用Base函數,因而咱們就給obj對象賦值了一個id成員變量,這個成員變量的值是」base」,關於call函數的用法。

 

代碼:

    function Person(name)  

    {  

       this.name=name;  

       this.showMe=function()  

            {  

               alert(this.name);  

            }  

    };  

 

    Person.prototype.from=function()  

    {  

      alert('I come from prototype.');  

    }  

 

    var one=new Person('js');  

 

    one.showMe();//js,這個結果沒有什麼好奇怪的  

    one.from();//I come from prototype.,這個結果有一點奇怪吧  

    alert(one.constructor);//function Person(name) {...}  

    alert(Person.prototype.constructor);//function Person(name) {...}  

再看看繼承是如何實現的

function Person(name)  

{  

   this.name=name;  

   this.showMe=function()  

        {  

           alert(this.name);  

        }  

};  

 

Person.prototype.from=function()  

{  

  alert('I come from prototype.');  

}  

function SubPerson()  

{  

}  

SubPerson.prototype=new Person();  

 

var subOne=new SubPerson();  

subOne.from();//I come from prototype.  

alert(subOne.constructor);//function Person(name) {...};  

alert(SubPerson.prototype.constructor);//function Person(name) {...};

繼承的實現很簡單,只須要把子類的prototype設置爲父類的一個對象便可。注意這裏說的但是對象哦!

 

那麼經過prototype屬性實現繼承的原理是什麼呢?仍是先看圖形說明,而後編寫代碼進行驗證。 

注意:紅色的方框就是把子類與父類連接起來的地方。這個就應該是傳說中的prototype鏈了吧。下面有代碼進行驗證

js代碼:

    function Person(name)  

    {  

       this.name=name;  

       this.showMe=function()  

            {  

               alert(this.name);  

            }  

    };  

 

    Person.prototype.from=function()  

    {  

      alert('I come from prototype.');  

    }  

    var father=new Person('js');//爲了下面演示使用showMe方法,採用了js參數,實際多采用無參數  

    alert(father.constructor);//查看構造函數,結果是:function Person(name) {...};  

    function SubPer()  

    {  

    }  

    SubPer.prototype=father;//注意這裏  

    SubPer.prototype.constructor=SubPer;  

 

    var son=new SubPer();  

    son.showMe();//js  

    son.from();//I come from prototype.  

    alert(father.constructor);//function SubPer(){...}  

    alert(son.constructor);//function SubPer(){...}  

    alert(SubPer.prototype.constructor);//function SubPer(){...}  

根據上圖的prototype鏈,還有代碼的結果,我想應該明白爲何使用prototype可以實現

JS中的繼承了吧。



 

到此,上面的圖應該很清楚了。再來一張手繪版的,有點不清楚哈

相關文章
相關標籤/搜索