咱們建立的每個函數都有一個prototype
(原型)屬性,這個屬性指向的是經過調用構造函數來建立出來的對象實例的原型對象,這個原型對象可讓全部對象實例共享它所包含的屬性和方法。bash
function Person () {
}
Person.prototype.name = "xiao";
Person.prototype.sayName = function () {
alert('this.name')
}
var person1 = new Person();
var person2 = new Person();
person1.sayName() // "xiao"
console.log(person1.name == person2.name) // "true"
複製代碼
上面的例子當中咱們建立了一個構造函數Person
,並經過它的prototype
屬性在它的原型對象中定義了name
屬性並賦值,而後經過調用構造函數Person
實例化出來兩個對象實例,經過打印出來的值咱們能夠得知,person1
和person2
共享了原型對象中的屬性和方法。閉包
咱們知道每一個函數都有一個prototype
屬性指向函數的原型對象。在默認狀況下,全部原型對象都有一個constructor
(構造函數)屬性,這個屬性指向了prototype
屬性所在的函數,好比前面的例子中,Person.prototype.constructor
就指向Person
。
另外,當調用構造函數建立一個新實例後,該實例的內部將包含一個__porto__
屬性(僅在Firefox、Safari、Chrome中支持),這個屬性指向的就是構造函數的原型對象。由此咱們能夠得出如下圖示的結論:app
經過代碼來驗證:函數
# 實例和原型對象之間的關係
console.log(person.__proto__ == Person.prototype) // true
# 也能夠經過isPrototypeOf()和ES5中的Object.getPrototypeOf()方法來判斷
console.log(Person.prototype.isPrototypeOf(person1)) // true
console.log(Object.getPrototypeOf(person) === Person.prototype) // true
# 原型對象和構造函數的關係
console.log(Person.prototype.constructor == Person) // true
複製代碼
經過前面咱們對構造函數,對象實例和原型對象三者關係的描述可知,實例都包含了指向原型對象的內部指針。
那麼假如如今咱們有兩個構造函數A跟B,咱們讓構造函數A的原型對象等於構造函數B的實例,根據前面的推論,這個時候A的原型對象就包含指向B的原型對象的指針,再假如又有一個構造函數C,讓A的原型對象等於C的實例,上述關係依舊成立,以此類推便造成了實例與原型的鏈條,即原型鏈,它主要做爲JS中實現繼承的主要方法。post
原型鏈的基本實現ui
function SuperType() {
this.property = true;
}
SuperType.prototype.getSuperValue = function() {
return this.property;
}
# 繼承了SuperType
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function() {
return this.subproperty;
}
var instance = new SubType();
console.log(instance.SuperValue()); // true
複製代碼
在上面的代碼中,咱們沒有使用SubType
默認的原型,而是將SuperType
的實例賦給它,重寫了SubType
的原型對象;這樣一來SubType.prototype
的內部便具備一個指向SuperType
原型的指針,原來存在於SuperType
的實例中的全部屬性和方法,如今也存在於SubType.prototype
中了。
instance
同理,還要注意的是因爲SubType
的原型指向了SuperType
的原型,而SuperType
的原型的constructor
屬性指向的是SuperType
構造函數,那麼instance.constructor
也就指向了SuperType
this
以下圖所示藍色的線就表明了原型鏈spa
當訪問一個實例屬性或方法時,在經過原型鏈實現繼承的狀況下,首先會在實例中搜索該屬性,在沒有找到屬性或方法時,便會沿着原型鏈繼續往上搜索,直到原型鏈末端纔會停下來。
這裏還有一個重要的點,事實上全部引用類型默認都繼承了Object
,而這個繼承也是經過原型鏈實現的,也就是說,全部函數的默認原型都是Object
的實例,這也是全部自定義類型都會繼承toString()
、valueOf()
等默認方法的根本緣由。prototype
Object.prototype的原型
3d
既然全部類型默認都繼承了Object
,那麼Object.prototype
又指向哪裏呢,答案是null
,咱們能夠經過下面的代碼打印試試看:
console.log(Object.prototype.__proto__ === null) // true
複製代碼
null
即沒有值,也就是說屬性或方法的查找到Object.prototype
就結束了。
這個時候,咱們就能夠看到完整的原型鏈關係圖以下:
結尾
系列文章: