prototype
在JavaScript中队秩,每一個函數(shù)都有一個prototype屬性狼讨,且prototype屬性是函數(shù)才會有的屬性绰疤。
那么函數(shù)的prototype屬性到底指向的是哪眉睹?
function Person(){}
Person.prototype.name = 'kevin'
var p1 = new Person()
var p2 = new Person()
console.log(p1.name) // 'kevin'
console.log(p2.name) // 'kevin'
函數(shù)prototype屬性指向的是一個對象享完,這個對象正式是調(diào)用該構(gòu)造函數(shù)而創(chuàng)建的實例原型灼芭,也是p1和p2的原型。
那什么是原型般又?可以這樣理解:每一個JavaScript對象(null除外)在創(chuàng)建的時候就會與之關(guān)聯(lián)另一個對象彼绷,這個對象就是我們說的原型巍佑,每一個對象都會從原型“繼承”屬性。
繼承意味著復(fù)制操作寄悯,然而JavaScript默認(rèn)并不會復(fù)制對象的屬性萤衰,相反,JavaScript只是在兩個對象之間創(chuàng)建一個關(guān)聯(lián)猜旬,這樣脆栋,一個對象就可以通過委托訪問另一個對象的屬性和函數(shù),所以與其叫做繼承洒擦,委托的說法反而更加準(zhǔn)確些椿争。--《你不知道的JavaScript》
__proto__
每一個JavaScript對象(除了null)都具有一個屬性__proto__,這個屬性會指向該對象的原型熟嫩。
function Person(){}
// Person.prototype === p1.__proto__ // true
constructor
每一個原型都有一個constructor屬性秦踪,屬性指向指向關(guān)聯(lián)的構(gòu)造函數(shù)。
function Person(){}
var p1 = new Person()
// Person.prototype.constructor === Person // true
// p1.__proto__.constructor === Person // true
// Object.getPrototypeOf(p1) === Person // true
實例與原型
當(dāng)讀取實例的屬性時掸茅,如果找不到椅邓,就會查找與對象關(guān)聯(lián)的原型中的屬性,如果還查不到倦蚪,就去找原型的原型希坚,一直找到頂層位置。這就是實例屬性查找機制陵且,也是原型鏈的概念裁僧。
function Person(){}
Person.prototype.name = 'jack'
var p1 = new Person()
p1.sex = '男'
p1.sex // 男
p1.name // jack
p1.age // null
上述代碼中,當(dāng)打印p1.sex的時候慕购,因為p1.sex是添加了屬性聊疲,所以能正常打印出來。但打印p1.name時沪悲,p1的屬性中時不存在的获洲,那么就會在p1的原型中p1.__proto__去找,也就是Person.prototype中去找殿如。當(dāng)打印p1.age的時候贡珊,原型中也不存在,那么就是在原型的原型中去找涉馁,那么原型的原型是什么门岔?
其實原型也是一個對象,對象的原型__proto__也就是Object.prototype的原型
Object.prototype.__proto__ === null // true
null表示“沒有對象”烤送,即該處不應(yīng)該有值
Object.prototype.__proto__的值為null寒随,其實就是說Object.prototype是沒有原型的
圖中由相互關(guān)聯(lián)的原型組成的鏈狀結(jié)構(gòu)(藍色線條部分)就是原型鏈