JavaScript溫故而知新——原型和原型鏈

1、原型模式

咱們建立的每個函數都有一個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實例化出來兩個對象實例,經過打印出來的值咱們能夠得知,person1person2共享了原型對象中的屬性和方法。閉包

構造函數,原型對象和對象實例的關係

咱們知道每一個函數都有一個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
複製代碼

2、原型鏈

經過前面咱們對構造函數,對象實例和原型對象三者關係的描述可知,實例都包含了指向原型對象的內部指針。
那麼假如如今咱們有兩個構造函數AB,咱們讓構造函數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就結束了。

這個時候,咱們就能夠看到完整的原型鏈關係圖以下:

結尾

系列文章:

相關文章
相關標籤/搜索