原型是javascript面向?qū)ο缶幊讨蟹浅V匾母拍睿也⒉皇悄敲慈菀锥E既豢吹揭粋€題目:闡述proto和prototype的關(guān)系。看到這個問題的時候,我的腦海浮現(xiàn)出一些概念,但卻說不出來。先來看一張圖

如果能看懂圖中的關(guān)系基本上就可以解釋出
*proto*和prototype的關(guān)系和區(qū)別了
所以接下來一一介紹圖中的一些概念
構(gòu)造函數(shù)
使用構(gòu)造函數(shù)創(chuàng)建對象

Person就是一個構(gòu)造函數(shù),通過new創(chuàng)建了person1對象實例
其實構(gòu)造函數(shù)就和普通函數(shù)沒有多大區(qū)別,首字母大寫只是約定俗成,不大寫照樣可以。關(guān)鍵是調(diào)用它的方式——通過new,那么這里又會牽扯到另一個問題,使用new調(diào)用后會內(nèi)部會執(zhí)行哪些操作
prototype
圖中可以看到在Person構(gòu)造函數(shù)下有一個prototype屬性。

這個并不是構(gòu)造函數(shù)專有,每個函數(shù)都會有一個prototype屬性,這個屬性是一個指針,指向一個對象,記住只有函數(shù)才有,并且通過bind()綁定的也沒有。

前面所說prototype屬性指向一個對象,那么這個對象是什么?
根據(jù)第一張圖片可以清晰看到,prototype指向Person.prototype。沒錯Person.prototype就是原型對象,也就是實例person1和person2的原型。
原型對象的好處是可以讓所有對象實例共享它所包含的屬性和方法
所以構(gòu)造函數(shù)和原型之間的關(guān)系為

proto
第一張圖中看到,在person1和person2實例對象下面有一個[[prototype]],其實沒有標準的方式可以訪問它,但是主流瀏覽器上在每個對象上(null除外)都支持一個屬性,那就是proto,這個屬性會指向該對象的原型


所以總結(jié)可得proto就是用來將對象與該對象的原型相連
在所有實現(xiàn)中都無法訪問到[[prototype]],但是可以通過一些方法來確定對象之間時候存在這種關(guān)系
instanceof,這個操作符只能處理對象(person1)和函數(shù)(帶.prototype引用的Person)之間的關(guān)系
person1 instanceof Person // true
isPrototypeOf,如果[[prototype]]指向調(diào)用此方法的對象,那么這個方法就會返回true
Person.prototype.isPrototypeOf(person1) // true
Person.prototype.isPrototypeOf(person2) // true
Object.getPrototypeOf這個方法返回[[Prototype]]的值,可以獲取到一個對象的原型
Object.getPrototypeOf(person1) === Person.prototype // true
constuctor
我們來繼續(xù)理解第一張圖中的關(guān)系,現(xiàn)在理解原型對象(PErson.prototype)下constructor屬性
這個屬性其實就是將原型對象指向關(guān)聯(lián)的構(gòu)造函數(shù)

再來看一些代碼

那豈不是實例person1也有.constructor屬性,其實沒有,通過原型鏈在原型Person.prtototype上面找到的
理順了這層關(guān)系,第一張圖就全部理解完了,是不是差不多就可以解釋出proto和prototype的關(guān)系和區(qū)別呢
原型鏈
我們既然探索完了他們的關(guān)系,那我們來繼續(xù)探索一下原型和原型鏈的奧秘所在,其實原型鏈就是依托proto和prototype連接起來的
在探索之前我們先來理解一下實例屬性和原型屬性的關(guān)系,見代碼

上面代碼中在實例屬性和原型屬性都有一個名為name的屬性,但是最后輸出來的是實例屬性上的值
當我們讀取一個屬性的時候,如果在實例屬性上找到了,就讀取它,不會管原型屬性上是否還有相同的屬性,這其實就是屬性屏蔽。即當實例屬性和原型屬性擁有相同名字的時候,實例屬性會屏蔽原型屬性,記住只是屏蔽,不會修改,原型屬性那個值還在
但是如果在實例屬性上沒有找到的話,就會在實例的原型上去找,如果原型上還沒有,就繼續(xù)到原型的原型上去找,直到盡頭,這個盡頭是啥?不急,等會說

上面代碼中person1實例并沒有name屬性,但仍然可以輸出值,就是在原型上找到的
如何檢測一個屬性存在于實例中,還是原型中?
使用方法hasOwnProperty,屬性只有存在于實例中才會返回true

既然講到了方法,就再補充一些方法
in操作符
前面提到hasOwnProperty方法可用于檢測屬性是否是實例屬性,in則會遍歷所有屬性,不管是實例上的,還是原型上的
in操作符有兩種使用方式,單獨使用和在for-in循環(huán)中使用,先上基礎(chǔ)代碼

單獨使用

Object.keys() 此方法可以獲取對象的所有可枚舉的屬性的名字
var keys = Object.keys(person1)
console.log(keys) // ["name"]
var keys = Object.keys(Person.prototype)
console.log(keys) // ["age"]
好了方法講完了,繼續(xù),假如在原型對象Person.prototype還是沒有找到這個屬性,會停止嗎?前面已經(jīng)說了,還會繼續(xù)找,這并不是盡頭。原型對象也是對象,所以它也有proto屬性,連接它的原型,原型對象Person.prototype的原型就是Object.prototype這個大boss,所有原型對象都是Object構(gòu)造函數(shù)生成的
正是因為所有的原型最終都會指向Object.prototype,所以對象的很多方法其實都是繼承于此,比如toString()、valueOf(),前面用到的hasOwnProperty,甚至是.constructor、proto
Object.prototype有原型嗎?

沒有,為null,所以它就是前面所提到的盡頭
總結(jié)成一張圖
