首先來看三個的各自含義函數
不管何時,只要建立函數,就會根據規則爲該函數建立一個 prototype屬性,這個屬性指向函數的原型對象。在默認狀況下,全部的原型對象,都會自動得到一個constructor屬性。這個屬性包含一個指向 prototype 屬性所在函數的指針。
在建立了自定義構造函數以後,其原型對象默認只會取得 constructor 屬性和從Object繼承一些方法。
當調用構造函數建立一個新實例後,該實例的內部將包含一個指針(內部屬性),指向構造函數的原型對象
例如:prototype
// 定義函數. 會默認爲該函數建立prototype屬性 function Person(){} // 建立實例對象, 實例對象會有默認的proto 屬性 指向原型對象 var p = new Person()
圖示:
指針
function foo(){} f1 = new foo;
圖示:
code
注意:
原型對象Function.prototype的constructor屬性指向構造函數Function();實例對象Object和Foo自己沒有constructor屬性,須要繼承原型對象Function.prototype的constructor屬性。對象
function Foo(){}; var f1 = new Foo; console.log(Function.prototype.constructor === Function);//true console.log(Foo.constructor === Function);//true console.log(Foo.hasOwnProperty('constructor'));//false console.log(Object.constructor === Function);//true console.log(Object.hasOwnProperty('constructor'));//false
其實,在對象去查找一個屬性的時候,會如今對象自己上查找,若是不存在,則在其原型對象上查找,一直查找到null爲止。這種經過原型層層鏈接起來的就稱爲成了原型鏈
注意: 原型對象能夠被修改,能夠被重寫。注意修改和重寫的區別:blog
function Foo(){} foo.prototype.name = 'fun' var f1 = new Foo; alert(f1.name); // fun 能夠訪問到原型對象上的屬性
function Foo(){} Foo.prototype = { name:"foo" } var f1 = new Foo; alert(f1.name); // fun 能夠訪問到原型對象上的屬性
注意當以這種字面量來建立,雖然結果是正確的可是 constructor 並不在指向 Foo 函數了。 而如今咱們徹底重寫了prototype 對象了。(就是改變了Foo.prototype的指向一個新建立的對象)所以,constructor屬性指向新對象的constructor屬性(新對象由Objecct建立出來的,所以指向了Object構造函數)繼承
console.log(f1 instanceof Objecct) // true console.log(f1 instanceof Foo) // true console.log(f1.constructor == Foo) // false console.log(f1.constructor == Object) // true
因此一般會在改變prototype時指定constructor屬相原型鏈
unction Foo(){} Foo.prototype = { constructor: Foo, name:"foo" } var f1 = new Foo; alert(f1.name); // fun 能夠訪問到原型對象上的屬性
其實原型對象和實例對象之間鏈接就一個指針,而非副本,這樣鬆散的鏈接關係, 就可以讓咱們在原型對象作的任何操做,在實例上當即反應出來。原型
function Foo(){} f1 = new Foo; // 這裏改變對象自己, 此時 實例對象和構造函數的原型對象是同一地址 Foo.prototype.sayHello = function(){ console.log("hello") } f1.sayHello() // 'hello'
請記住,實例中的prototype指向原型對象,在建立時就構造函數已經決定了。 不會隨着構造函數的原型對象指針的改變而發生改變。io
function Foo(){} f1 = new Foo; // 這裏改變了指向。 此時 實例對象和構造函數的原型對象不在指向同一地址了 Foo.prototype = { constructor: Foo, sayHello : function(){ console.log("hello") } } f1.sayHello() // erro
重寫原型對象切斷了現有原型與任何以前已經存在的對象實例之間的聯繫,以前任何實例對象它們的引用仍然是最初的原型。而現有構造函數,以及以後建立的實例對象會指向重寫以後的原型對象。