再上一篇有簡單講過原型:JavaScript(5)--- 面向對象 + 原型javascript
講原型鏈知識以前,先說幾個重要的結論。html
一、原型鏈就是 對象的__proto__所鏈接的鏈狀結構 二、prototype 屬性是函數獨有的 三、__proto__ 屬性是對象獨有的,實例原型(Object.prototype)也是對象,因此也會有__proto__屬性
下面咱們一步一步來說解原型鏈java
咱們先使用構造函數建立一個對象:git
function Person() { } var p = new Person(); p.name = 'xiaoxiao'; console.log(p.name); //xiaoxiao
概念
它是 函數獨有的屬性,它從一個函數指向另外一個對象,表明這個對象是這個函數的原型對象,這個對象也是當前函數所建立的實例的原型對象。angularjs
prototype設計之初就是爲了實現繼承,讓構造函數建立的全部實例,都可以共享這個原型屬性和方法。github
有了prototype咱們不須要爲每個實例建立重複的屬性方法,而是將屬性方法建立在構造函數的原型對象上(prototype)。那些不須要共享的才建立在構造函數中。面試
示例
函數
function Person(){ } Person.prototype.age=18; //原型屬性 var p1 = new Person(); var p2 = new Person(); console.log(p1.age);//18 console.log(p2.age);//18
思考
這個函數的 prototype 屬性到底指向的是什麼呢?
其實,函數的 prototype 屬性指向了一個對象,這個對象正是調用該構造函數而建立的實例的原型 。
思考
那麼什麼是原型呢?.net
每個 JavaScript 對象 (null 除外 ) 在建立的時候就會與之關聯另外一個對象,這個對象就是咱們所說的原型,每個對象都會從原型 」 繼承 」 屬性。prototype
這裏p1和p2就是實例對象,而Person.prototype就是它們的原型對象。p1和p2能夠去繼承原型對象的方法和屬性。
讓咱們用一張圖表示構造函數和實例原型之間的關係:
概念
__proto__屬性是對象(包括函數,函數也是對象)獨有的。__proto__屬性是從一個對象指向另外一個對象,該屬性指向的就是該對象的原型對象(也能夠理解爲父對象)。
示例
function Person(){ } var p = new Person(); console.log(p.__proto__ === Person.prototype);//true
更新下關係圖
__proto__一般稱爲隱式原型,prototype爲顯示原型,那咱們能夠說一個對象的隱式原型指向了該對象的構造函數的顯示原型。那麼咱們在顯示原型上定義的屬性方法,
經過隱式原型傳遞給了構造函數的實例。這樣一來實例就能很容易的訪問到構造函數原型上的方法和屬性了。
概念
constructor是對象纔有的屬性,它是從一個對象指向一個函數的。指向的函數就是該對象的構造函數。
注意了 實例原型也是對象,因此也會有constructor屬性,咱們來驗證一下
function Person(){ } console.log(Person === Person.prototype.constructor);//true console.log(person.constructor); // ƒ Person(){}
再更新下關係圖
總結 經過上面的演示說明,咱們能夠得出
function Person(){ } var person = new Person(); console.log(person.__proto__ === Person.prototype);//true console.log(Person === Person.prototype.constructor);//true
瞭解了構造函數、實例原型、和實例之間的關係,接下來咱們講講實例和原型的關係
當讀取實例的屬性時,若是找不到,就會查找與對象關聯的原型中的屬性,若是還查不到,就去找原型的原型,一直找到最頂層爲止。
示例
function Person(){ } var person = new Person(); Person.prototype.name='張三'; person.name='李四'; console.log(person.name);//李四 delete person.name; console.log(person.name);//張三
在這個例子中,咱們設置了 person 的 name 屬性,因此咱們能夠讀取到爲 ’李四’ ,當咱們刪除了 person 的 name 屬性時,讀取 person.name ,從 person 中找不到
就會從 person 的原型中查找,name爲 ’張三’ 。可是萬一Person.prototype原型中尚未找到呢?那會到原型的原型去查找。也就是Object.prototype
示例
function Person(){ } var person = new Person(); Person.prototype.name='李四'; person.name='張三'; console.log(person.name);//張三 delete person.name; console.log(person.name);//李四 Object.prototype.name='obj'; delete Person.prototype.name; console.log(person.name);//obj
因此原型對象是經過 Object 構造函數生成的,結合以前所講 , 實例的 _proto_ 指向構造函數的 prototype, 所
再更新下關係圖
那 Object.prototypey也是對象,那它也應該會有原型。只不過有是有,只是爲null
, 因此查到 Object.prototype 就能夠中止查找了 。
因此最後一張關係圖就是
總結
圖中由相互關聯的原型組成的鏈狀結構就是原型鏈,也就是紅色的這條線
。
一、JavaScript深刻之從原型到原型鏈 很是感謝
別人罵我胖,我會生氣,由於我內心認可了我胖。別人說我矮,我就會以爲可笑,由於我內心知道我不可能矮。這就是咱們爲何會對別人的攻擊生氣。 攻我盾者,乃我心裏之矛(3)。