深刻挖掘原型鏈

1.原型對象,實例對象與構造函數

若是想要深刻理解原型鏈,首先須要明確知道什麼時原型對象,什麼是實例對象,以及原型對象,實例對象與構造函數三者之間的關係。
首先,實例對象是指經過關鍵字new,由構造函數構造出的對象實例對象能夠有多個,而且實例對象會繼承它的原型對象上的全部屬性。數組

function Foo() {

    }
    var f1=new Foo();
    var f2=new Foo();

f1f2就是由構造函數Foo經過關鍵字new建立的兩個實例對象。
同一個構造函數的實例對象的原型對象是同一個,是構造函數的prototype屬性,在實例對象上能夠經過__proto__屬性獲取。即:函數

console.log(f1.__proto__ === Foo.prototype);//true
    console.log(f2.__proto__ === Foo.prototype);//true
    console.log(f1.__proto__ === f2.__proto__);//true

所以當咱們在原型對象上添加屬性或方法時,全部的實例對象都會繼承該屬性或方法,咱們能夠將一些公用的方法定義在Foo.prototype上。spa

2.原型對象,實例對象和構造函數三者的關係

每一個實例對象的原型對象上都有一個constructor屬性,這個屬性指向實例對象的構造函數,實例對象能夠從它的原型對象上繼承該屬性。
三者的關係聽起來十分繞口,可是用代碼體現就很清晰了:
實例對象f1,構造函數Foo,原型對象Foo.prototype===f1.__proto__prototype

console.log(Foo.prototype.constructor === Foo);//true
    console.log(f1.__proto__.constructor === Foo);//true
    console.log(f1.constructor === Foo);//true
 console.log(f1.constructor === f1.__proto__.constructor);//true

3.JavaScript的原型鏈規則

1.js中規定,全部的對象都有本身的原型對象,原型對象和和函數也是對象,因此他們也有本身的原型對象(__proto__),所以會造成原型鏈。
2.js中讀取屬性和方法的規則:js引擎會首先在對象自己查找屬性和方法,若是找不到就會沿着原型鏈逐層向上查找,最終找不到就會返回undefined。若是找到了就不會再繼續查找,因此當一個實例對象和它的原型對象上具備同名屬性或方法時,只會查找到對象自己的屬性或方法。
使用圖示能夠更好地理解原型鏈:3d

function Foo() {

    }
    var f1 = new Foo();

以上這段代碼:
首先有實例對象,構造函數和原型對象
原型對象的constructor指向構造函數,實例對象繼承的constructor也是指向構造函數,實例對象和構造函數的__proto__prototype指向同一個原型對象。
原型鏈1.PNG
而後,由於Foo.prototype也是一個對象,他也具備自身的原型對象__proto__,由三者關係咱們能夠知道,Foo.prototype.__proto__.constructor應該指向Foo.prototype的構造函數,輸出結果是Object,即Foo.prototype.__proto__.constructor===Object,而且Object.prototype也應該有本身的原型對象,輸出爲null
因此有:
原型鏈2.PNG
再而後,構造函數FooObject也是實例對象,他們也應該由本身的原型對象__proto__,而全部的函數都是由構造函數Function構造的,因此Object.__proto__===Function.prototypeFoo.__proto__===Function.prototype,Object.__proto__===Foo.__proto__,而且Function.prototype也有本身的原型對象__popto__,指向了Object.prototype,能夠畫出:
原型鏈3.PNG
原型鏈圖示
這就是一條完整的原型鏈了,從圖中咱們能夠發現:
Object.prototype是原型鏈的盡頭,再向上就是null了,null是無心義的,一次全部的對象都繼承了Object.prototype上的屬性和方法。code

4.提一個小問題,我想讓Foo的全部實例對象都具備數組的屬性和方法,應該怎麼作呢?

經過上面的分析,咱們知道,實例對象共用的屬性和方法都應該定義在了他們的原型對象上,因此數組的屬性和方法都在Array.prototype上,
實例對象f1,f2共用的屬性和方法來自Foo.prototype,因此咱們能夠:
Foo.prototype=Array.prototype
這樣f1,f2就繼承了數組的屬性和方法,可是咱們須要注意一點,此時輸出f1.constructor,來觀察f1,f2的構造函數會發現它們已經成了Array
這是由於constructor屬性一樣是從原型對象Foo.prototype上繼承而來的,因此當Foo.prototype上的constructor屬性發生變化時,實例對象f1constructor也會變化。因此咱們若是不想讓構造函數發生變化的話,須要重寫一次Foo.prototypeconstructor屬性,
Foo.prototype=Array.prototype
Foo.prototype.constructor=Foo對象

因此咱們須要注意,在修改實例對象的原型對象以後,也要記得修改constructor屬性blog

相關文章
相關標籤/搜索