一.什麼是原型?
原型是一個對象,其餘對象能夠經過它實現屬性繼承。
簡單的說就是任何一個對象均可以成爲原型函數
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,證實不存在此方法或屬性。這樣一層一層查找實例上的原型上的屬性就構成一條原型鏈。
好了就到這裏了,有不對的地方請指正~~~~