問(wèn)題
初學(xué)js的同學(xué)驾胆,總是搞不清楚js中的原型是什么東西,看著控制臺(tái)打印出來(lái)的一串串__proto__跛锌,迷惑不已弃秆。
例如我定義一個(gè)Person,創(chuàng)建一個(gè)實(shí)例p髓帽,并打印實(shí)例菠赚。
function Person(){}
var p = new Person();
console.log(p)
圖中,打印出來(lái)一個(gè)Person的實(shí)例對(duì)象p郑藏,
這個(gè)對(duì)象有個(gè)__proto__ 屬性衡查,這個(gè)是什么東西?
__proto__屬性下又有constructor屬性和__proto__屬性必盖。
constructor是什么拌牲,為什么打印結(jié)果是 Person()?
另外一個(gè)__proto__是什么歌粥?
為了解答上邊的問(wèn)題塌忽,我們需要了解一些相關(guān)概念。
一失驶、原型
prototype
首先土居,說(shuō)明一下,JS中,萬(wàn)物皆對(duì)象装盯。
每個(gè)函數(shù)對(duì)象都有一個(gè)屬性prototype(函數(shù)對(duì)象特有屬性)坷虑,這個(gè)屬性是一個(gè)引用,指向一個(gè)對(duì)象埂奈,這個(gè)對(duì)象的作用就是包含所有實(shí)例共享的屬性和方法迄损。我們把這個(gè)對(duì)象就叫做原型對(duì)象,也叫顯式原型账磺。
__proto__
每個(gè)對(duì)象都有一個(gè)屬性__proto__芹敌,也可稱為隱式原型,對(duì)象的隱式原型指向創(chuàng)建該對(duì)象的構(gòu)造函數(shù)的原型(prototype)垮抗。
constructor
函數(shù)的原型對(duì)象有一個(gè)constructor屬性氏捞,這個(gè)屬性是一個(gè)引用,用于指向原構(gòu)造函數(shù)冒版。
關(guān)系
我們?cè)趺蠢斫馍线叺母拍钜壕ィ鼈冎g又有什么聯(lián)系呢?
我們不妨打印出來(lái)p.__proto__屬性:
可以看到辞嗡,打印出來(lái)是一個(gè)對(duì)象捆等,對(duì)象里邊有個(gè)屬性constructor。
constructor是什么呢续室,打印如下:
可以看到栋烤,打印出來(lái)是函數(shù),代表的就是Person構(gòu)造函數(shù)本身.
再依次打印出來(lái)Person構(gòu)造函數(shù)的原型Person.prototype挺狰,
和其原型的屬性constructor:
從上圖我們就可以得出:
1.實(shí)例對(duì)象p有屬性__proto__ 指向的就是創(chuàng)建它的構(gòu)造函數(shù)的原型對(duì)象Person.prototype明郭。
2.構(gòu)造函數(shù)的原型對(duì)象Person.prototype的屬性constructor指向Person構(gòu)造函數(shù)本身。
我們可以驗(yàn)證一下:
但是丰泊,可能又有些同學(xué)有疑惑了薯定,那既然所有對(duì)象都有__proto__屬性,
那構(gòu)造函數(shù)Person()的屬性__proto__指向誰(shuí)呢趁耗?
當(dāng)然是指向它的構(gòu)造函數(shù)的原型對(duì)象了沉唠。
函數(shù)的構(gòu)造函數(shù)就是Function(),因此這里的__proto__指向Function.prototype苛败。
那原型對(duì)象也是對(duì)象满葛,它的__proto__屬性指向誰(shuí)呢?
同理,指向它的構(gòu)造函數(shù)的原型對(duì)象罢屈,即Object.prototype嘀韧。
這里,我們就不得不提一下缠捌,原型鏈的概念了锄贷。
原型鏈
原型鏈?zhǔn)且环N機(jī)制译蒂,指的是js中,每個(gè)對(duì)象都有一個(gè)屬性__proto__谊却,指向它的構(gòu)造函數(shù)的原型對(duì)象柔昼。原型對(duì)象也是一個(gè)對(duì)象,因此也有__proto__屬性指向原型對(duì)象的原型對(duì)象炎辨,這樣一層層向上直到對(duì)象的原型對(duì)象為空(Object的原型對(duì)象Object.prototpye的屬性__proto__為null)捕透。
因此,例子中原型鏈的關(guān)系如下:
p.__proto__ 指向 Person.prototype碴萧,
Person.prototype.__proto__指向的就是Object.prototype乙嘀,
Object.prototpye.__proto__ 指向null
為了理解上邊例子的原型鏈關(guān)系,我們畫一張圖來(lái)增加理解:
至此破喻,上邊的問(wèn)題是不是心里已經(jīng)有答案了呢虎谢。
總結(jié)
1.每個(gè)對(duì)象都有一個(gè)__proto__屬性,指向創(chuàng)建它的構(gòu)造函數(shù)的原型對(duì)象曹质。
作用:構(gòu)成原型鏈婴噩,用于實(shí)現(xiàn)基于原型的繼承。
2.函數(shù)除了有__proto__屬性羽德,還有一個(gè)prototype屬性讳推,用來(lái)指向函數(shù)的原型對(duì)象。
作用:用于實(shí)現(xiàn)基于原型的繼承和屬性共享玩般。
因此,你會(huì)在很多地方見(jiàn)到有類似這樣的寫法:
function Person(){}
Person.prototype.hello = function(){
console.log("hello")
}
上邊代碼表示礼饱,所有Person創(chuàng)建的實(shí)例對(duì)象都可以共享hello方法坏为。
3.構(gòu)造函數(shù)的原型對(duì)象有屬性constructor,指向構(gòu)造函數(shù)本身镊绪。
PS:歡迎關(guān)注公眾號(hào):「如若清風(fēng)」匀伏,一起交流學(xué)習(xí)。