深入理解原型和原型鏈

I O發表於2018-05-02

我們創造的每一個函式都有一個prototype(原型)屬性。這個屬性是一個指標,指向原型對 象。在預設情況下,所有的原型物件都會有一個constructor(建構函式)屬性,這個屬性包含一個指向prototype屬相所在的指標。當呼叫建構函式建立一個新例項之後,該例項內部將包含一個指標(內部屬性),指向建構函式的原型物件。

建構函式建立物件

一:什麼是原型?每一個javascrip物件(除null)在建立時都會與之關聯另一個物件,這個物件就是我們所說的原型,每一個物件都會從原型繼承。

讓我們用一張圖表示建構函式和例項原型之間的關係:


深入理解原型和原型鏈

二:每一個JavaScript物件(除了 null )都具有的一個屬性,叫__proto__(內部屬性),這個屬性會指向該物件的原型。

function Person() {

}
var person = new Person();
console.log(person.__proto__ === Person.prototype); // true複製程式碼

可以有以下關係圖:

å®ä¾ä¸å®ä¾ååç关系å¾

三: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 = "kevin";
var person1 = new person();
person1.name = "disy";
console.log(person1.name);
複製程式碼

在瀏覽器中操作得到結果:

深入理解原型和原型鏈

可以看出。刪除例項中的name後,向上查詢到了原型中的name屬性。

原型的原型

原型是一個物件,我們可以用最原始的方式來建立它:

var obj = new Object();
obj.name = 'Kevin'
console.log(obj.name) // Kevin複製程式碼

其實原型物件就是通過 Object 建構函式生成的,結合之前所講,例項的 __proto__ 指向建構函式的 prototype ,所以我們再更新下關係圖:

ååçåå关系å¾

原型鏈

文章的開頭就講了:每個建構函式都有一個原型物件,原型物件都包含一個指向建構函式的指標,而例項都包含一個指向原型物件的內部指標 .

假如我們讓原型物件等於另一個型別的例項。此時,原型物件將包含一個指向另一個原型的指標。假如,另一個原型又是另一個型別的例項。層層遞進,就構成了例項與原型的鏈條。

注意:Object.prototype的原型呢?

console.log(Object.prototype.__proto__ === null) // true複製程式碼

引用阮一峰老師的 《undefined與null的區別》 就是:

null 表示“沒有物件”,即該處不應該有值。

所以 Object.prototype.__proto__ 的值為 null 跟 Object.prototype 沒有原型,其實表達了一個意思。

所以查詢屬性的時候查到 Object.prototype 就可以停止查詢了。

最後一張圖的更新:

ååé¾ç¤ºæå¾


圖中的相互的鏈狀結構的關係組成原型鏈,也就是藍色部分。










 參考: 《JavaScript高階程式設計》   

               冴羽的部落格



相關文章