原型,原型鏈函數
原型:在JavaScript中原型是一個prototype對象,用於表示類型之間的關係。學習
原型鏈:JavaScript萬物都是對象,對象和對象之間也有關係,並非孤立存在的。對象之間的繼承關係,在JavaScript中是經過prototype對象指向父類對象,直到指向Object對象爲止,這樣就造成了一個原型指向的鏈條,專業術語稱之爲原型鏈。this
咱們先使用構造函數建立一個實例對象 person :spa
function Person() {}
var person = new Person(); person.name = 'name'; console.log(person.name) // name
在這個例子中,Person就是一個構造函數,咱們使用new建立了一個實例對象person。接下來prototype
prototype 原型code
每一個函數都有一個prototype屬性,就是咱們常常在各類例子中看到的那個prototype,好比:對象
function Person() {}
// 雖然寫在註釋裏,可是你要注意:prototype是函數纔會有的屬性
Person.prototype.name = 'name'; var person1 = new Person(); var person2 = new Person(); console.log(person1.name) // name console.log(person2.name) // name
那這個函數的prototype屬性到底指向的是什麼呢?blog
其實,函數的prototype屬性指向了一個對象,這個對象正是調用該構造函數而建立的實例的原型,也就是這個例子中的person1和person2的原型。繼承
那麼什麼是原型呢?你能夠這樣理解:每個JavaScript對象(null除外)在建立的時候就會與之關聯另外一個對象,這個對象就是咱們所說的原型,每個對象都會從原型」繼承」屬性。ip
讓咱們用一張圖表示構造函數和實例原型之間的關係:
那麼咱們該怎麼表示實例與實例原型,也就是person和Person.prototype之間的關係呢,這時候咱們就要講到第二個屬性:
__proto__
這是每個JavaScript對象(除了null)都具備的一個屬性,叫__proto__,這個屬性會指向該對象的原型。
爲了證實這一點,咱們能夠在谷歌控制檯中輸入:
function Person() {}
var person = new Person(); console.log(person.__proto__ === Person.prototype); //true
因而咱們更新下關係圖:
既然實例對象和構造函數均可以指向原型,那麼原型是否有屬性指向構造函數或者實例呢 ?答案固然是有的,但也不全然 :
指向實例卻是沒有,由於一個構造函數能夠生成多個實例,可是原型指向構造函數卻是有的,這就要講到第三個屬性:construcotr,每一個原型都有一個constructor屬性指向關聯的構造函數
constructor
爲了驗證這一點,咱們一樣能夠在谷歌控制檯嘗試:
function Person() {}
console.log(Person === Person.prototype.constructor); //true
因此再更新下關係圖:
綜上咱們已經得出:
function Person() {}
var person = new Person(); console.log(person.__proto__ == Person.prototype) // true console.log(Person.prototype.constructor == Person) // true // 順便學習一個ES5的方法,能夠得到對象的原型 console.log(Object.getPrototypeOf(person) === Person.prototype) //true
瞭解了構造函數、實例原型、和實例對象之間的關係,接下來咱們講講實例和原型的關係:
實例與原型
當讀取實例的屬性時,若是找不到,就會查找與實例對象關聯的原型中的屬性,若是還查不到,就去找原型的原型,一直找到最頂層爲止。
舉個例子:
function Person() {}
Person.prototype.name = 'name'; var person = new Person(); person.name = 'name of this person'; console.log(person.name) // name of this person //刪除 person.name ; 則會找原型中的name delete person.name; console.log(person.name) // name
在這個例子中,咱們設置了person的name屬性,因此咱們能夠讀取到爲’name of this person’,當咱們刪除了person的name屬性時,讀取person.name,從person中找不到就會從person的原型也就是person.__proto__ == Person.prototype中查找,幸運的是咱們找到了爲’name’,可是萬一尚未找到呢 ?原型的原型又是什麼呢 ?
在前面,咱們已經講了原型也是一個對象,既然是對象,咱們就能夠用最原始的方式建立它,那就是:
var obj = new Object();
obj.name = 'name' console.log(obj.name) // name
因此原型對象是經過Object構造函數生成的,結合以前所講,實例的__proto__指向構造函數的prototype,因此咱們再更新下關係圖:
原型鏈
那Object.prototype的原型呢?
null,就是null,因此查到Object.prototype就能夠中止查找了
因此最後一張關係圖就是
最後說一下,圖中由相互關聯的原型組成的鏈狀結構就是原型鏈,也就是藍色的這條線。