- 大致理解原型的由來
在Javascript之父 Brendan Eich 在設計JS的開始過程,數據類型都是對象(Object),這一點和Java很相似,所以他考慮到要不要設計‘繼承機制’,本來js設計之初本來就是想設計一個簡單容易學習的腳本語言,本身其實是不需要“繼承機制”的,但是其數據都是對象,必須需要一種機制把對象連接起來,所以他最好還是設計了“繼承”,但是他沒有引入類的概念(當然現在的es6是有類了),因爲一旦引入了類,這就是大大增加了js的難易程度,這違背了設計之初只是爲了設計簡單的腳本語言的初衷。
Eich仿照c++和Java,都使用了new和在調用類的過程中都使用了constructor(構造函數),所以在js調用new的過程中,後面跟的不是類而是構造函數,如:function DOG(name){ this.name = name; } 對這個構造函數使用new,就會生成一個狗對象的實例。 var dogA = new DOG('大毛'); alert(dogA.name); // 大毛 //注意this的指向,這個就是指實例對象
但是如此,new對象還是會有缺點,就是創建的實例對象,無法共享屬性和方法,
function DOG(name){ this.name = name; this.species = '犬科'; } //然後,生成兩個實例對象: var dogA = new DOG('大毛'); var dogB = new DOG('二毛'); //這兩個對象的species屬性是獨立的,修改其中一個,不會影響到另一個。 dogA.species = '貓科'; alert(dogB.species); // 顯示"犬科",不受dogA的影響 //每一個實例對象,都有自己的屬性和方法的副本。這不僅無法做到數據共享,也是極大的資源浪費。
考慮到這些,Brendan Eich決定爲構造函數設置一個prototype屬性。這個屬性包含一個對象(以下簡稱"prototype對象"),所有實例對象需要共享的屬性和方法,都放在這個對象裏面;那些不需要共享的屬性和方法,就放在構造函數裏面。實例對象一旦創建,將自動引用prototype對象的屬性和方法。也就是說,實例對象的屬性和方法,分成兩種,一種是本地的,另一種是引用的。如下
function DOG(name){ this.name = name; } DOG.prototype = { species : '犬科' }; var dogA = new DOG('大毛'); var dogB = new DOG('二毛'); alert(dogA.species); // 犬科 alert(dogB.species); // 犬科 //現在,species屬性放在prototype對象裏,是兩個實例對象共享的。只要修改了prototype對象,就會同時影響到兩個實例對象。 DOG.prototype.species = '貓科'; alert(dogA.species); // 貓科 alert(dogB.species); // 貓科
- 原型之間的關係
-構造函數的prototype與構建的實例對象的原型是相等的
function Person() {} var person = new Person(); console.log(person.__proto__ === Person.prototype); // true
構造函數等於其實例對象的原型的構造函數function Person() {} var person = new Person(); console.log(person.__proto__ == Person.prototype) // true console.log(Person.prototype.constructor == Person) // true console.log(person.constructor === Person); // 順便學習一個ES5的方法,可以獲得對象的原型 console.log(Object.getPrototypeOf(person) === Person.prototype) // true
當讀取實例對象的屬性時,如果在對象中找不到,就會查找與對象關聯的原型中的屬性,如果還查不到,就去找原型的原型(如何理解這種話呢,就是對象是一直有原型的,而原型也是對象,比如Person.prototype其實就是一個對象,只不過他的原型就是Object.prototype),一直找到最頂層爲止。
-
原型鏈
簡單的回顧一下構造函數、原型和實例的關係:每個構造函數都有一個原型對象,原型對象都包含一個指向構造函數的指針,而實例都包含一個指向原型對象的內部指針。那麼假如我們讓原型對象等於另一個類型的實例,結果會怎樣?顯然,此時的原型對象將包含一個指向另一個原型的指針,相應地,另一個原型中也包含着一個指向另一個構造函數的指針。假如另一個原型又是另一個類型的實例,那麼上述關係依然成立。如此層層遞進,就構成了實例與原型的鏈條。這就是所謂的原型鏈的基本概念。——摘自《javascript高級程序設計》
那 Object.prototype 的原型呢?
console.log(Object.prototype.__proto__ === null) // true
引用阮一峯老師的 《undefined與null的區別》 就是:
null 表示“沒有對象”,即該處不應該有值。
所以 Object.prototype.__proto__ 的值爲 null 跟 Object.prototype 沒有原型,其實表達了一個意思。
所以查找屬性的時候查到 Object.prototype 就可以停止查找了。
最後一張關係圖也可以更新爲:
圖中由相互關聯的原型組成的鏈狀結構就是原型鏈,也就是藍色的這條線。
前端原型鏈
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.