我們創造的每一個函式都有一個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高階程式設計》
冴羽的部落格