JavaScript原型與原型鏈學習筆記

一.什麼是原型?
原型是一個對象,其餘對象能夠經過它實現屬性繼承。
簡單的說就是任何一個對象均可以成爲原型函數


prototype屬性: 咱們建立的每一個函數都有一個prototype屬性,這個屬性是一個指針,指向一個對象,而這個對象包含能夠有特定類型的全部實例共享的屬性和方法。這個對象就是原型對象(也就是某個對象的原型所引用的對象)。
1.總之只要建立了函數,該函數都有一個prototype屬性,指向函數的原型對象。this

如上圖,Person是一個函數,右側的方框就是它的原型。spa

 

2.默認狀況下全部原型對象都會自動得到一個constructor(構造函數)屬性,這個屬性包含一個指向prototype屬性所在函數的指針。prototype

簡單來講prototype的屬性值是一個對象(屬性的集合,咱們能夠給他設置各類值),默認的只有一個叫作constructor的屬性,指向這個函數自己。指針

下面就是一個原型對象的例子:code

 1 function Person() {   
 2             
 3         }
 4         Person.prototype.name="花花";
 5         Person.prototype.sex="女";
 6         Person.prototype.showName=function(){
 7                 console.log('個人名字叫:'+this.name+'我是:'+this.sex+'的');
 8             }
 9      
10         var p1=new Person(); 
11          
12         p1.showName();

      

      

因此在這個例子裏:原型對象Person.prototype的constructor屬性指向Person。對象

3.原型對象的內部還包括一個指針__proto__指向構造函數的原型對象。每一個對象都有一個__proto__屬性。
注意:Object.prototype是一個特例——它的__proto__指向的是nullblog

這個__proto__是一個隱藏的屬性,在FF,Safari和Ghrome支持。繼承


如上面的例子,Person是一個函數,p1對象是從Person函數new出來的,這樣p1對象就能夠調用Person.prototype中的屬性。由於每一個對象都有一個隱藏的屬性——「__proto__」,這個屬性引用了建立這個對象的函數的prototype。即:p1.__proto__ === Person.prototype
下面在上面的例子中添加下面代碼來驗證一下:ip

1 console.log(p1.__proto__ === Person.prototype);//ture

結果爲true證實他們是相等的

簡單分析一下:構造函數Person有一個prototype的屬性對象(即:Person.prototype),其中prototype屬性對象中會包括__proto__,constructor(構造函數)指向構造函數,還有一些添加的屬性。建立構造函數的實例對象p1,p1會有__proto__屬性,指向其原型Person.prototype。

看看下面的圖捋一捋

那麼問題來了,以前咱們說每一個對象都有一個__proto__屬性,函數也是一種對象,那麼函數天然也有__proto__了,函數也是被建立出來的。誰建立了函數呢?那就是——Function——注意這個大寫的「F」

演示代碼以下:

1 function fn1(a,b) {   
2             return a+b;
3     }
4     console.log(fn1(2,6));
5 
6     var fn2=new Function("a","b","return a+b")
7     console.log(fn2(6,6));

以上代碼中,第一種方式是比較傳統的函數建立方式,第二種是用new Functoin建立。注意:不推薦用第二種方式

 

綜上所述:第一個例子中的構造函數Person也是一個對象,因此它也存在__proto__屬性,指向它的原型Function.prototype。

(根據這個圖用下面的方法可自行驗證)

Function.prototype指向的對象也是一個普通的被Object建立的對象,因此Function.prototype指向的對象,它的__proto__也指向Object.prototype

 

      驗證一下:    

1 console.log(Function.prototype.__proto__);//結果是Object {}

      判斷原型的方法有下面三種:

1         console.log(Object.getPrototypeOf(Person));
2         console.log(Object.__proto__);//函數原型對象
3         console.log(Person.constructor.prototype);

Object.getPrototypeOf()方法是ECMAScript5新加的,主流瀏覽才能夠用。

總結一下:每一個函數都有一個prototype,即原型(指向函數的原型對象)。每一個對象都有一個__proto__屬性(指向構造函數的原型對象),可成爲隱式原型。
那麼原型就是構造函數的實例對象的__proto__屬性指向的構造函數的原型對象。

 

二.原型鏈

原型鏈:訪問一個對象的屬性時,先在基本屬性中查找,若是沒有,再沿着__proto__這條鏈向上找,這就是原型鏈

下面是一個原型鏈的例子:

 1 function Person(name,sex) {   
 2             this.name=name;
 3             this.sex=sex;
 4         }
 5         
 6         Person.prototype.show=function(){
 7                 console.log('個人名字叫:'+this.name+'我是:'+this.sex+'的');
 8             }
 9         Person.prototype.showName=function(){
10                 console.log('名字:'+this.name);
11             }
12               
13         function Worker(name,sex,job){
14             Person.call(this,name,sex);//繼承Person屬性
15             this.job=job;
16         }
17 Worker.prototype=Person.prototype;//這是原型鏈(通往父級的一條鏈上傳遞) 18 Worker.prototype.showJob=function(){//子級添加新方法 19 console.log(this.job); 20 }
21 Worker.prototype.show=function(){ 22 console.log('名字:'+this.name+'性別:'+this.sex+'工做:'+this.job); 23 }
24 var p2=new Worker('mumu','女','student'); 25 p2.showName(); 26 p2.show();

分析下例子:建立Person函數,並在Person的原型對象上建立show和showName函數

建立Worker函數,Worker原型對象繼承Person的原型對象 Worker.prototype = Person.prototype;並在Worker原型對象上覆蓋Person的原型對象上的show

函數。

那麼,建立Worker的實例對象p2,在調用函數showName()時會在實例自己進行查找,若沒有找到,再沿着__proto__這條鏈查找上一級原型對象,一層一層向上找(原型鏈頂端Object.prototype),直到找到爲止。

若是當找到__proto__屬性爲null時,返回 undefined,證實不存在此方法或屬性。這樣一層一層查找實例上的原型上的屬性就構成一條原型鏈。

 

好了就到這裏了,有不對的地方請指正~~~~

相關文章
相關標籤/搜索