兩條規(guī)則:
實(shí)例.__proto__ === 構(gòu)造函數(shù).prototype實(shí)例.屬性 === 如果自身有該屬性 ? 實(shí)例.屬性 : 實(shí)例.[__proto__]n次.屬性
關(guān)于規(guī)則2的解釋:
查找實(shí)例的屬性時,先判斷自身有沒有這個屬性,如果有,那么直接獲取。
否則,查找它的__proto__有沒有這個屬性,有的話,就是它,
否則,查找它的__proto__.__proto__有沒有這個屬性……
如果一直找不到,就是undefined。(此處必有蹊蹺……略
測試用例:(測試環(huán)境,Chrome 44,Win7)
1. 考察構(gòu)造函數(shù)和實(shí)例
var F=function(){}; //構(gòu)造函數(shù)F
F.prototype={}; //先設(shè)置構(gòu)造函數(shù)的prototype
var f=new F; //造一個實(shí)例
console.assert(f.__proto__===F.prototype); //根據(jù)規(guī)則1
console.assert(f.a===undefined); //實(shí)例還沒有這個屬性
F.prototype.a=1; //給prototype增加一個屬性
console.assert(f.a===f.__proto__.a); //根據(jù)規(guī)則2
console.assert(f.a===F.prototype.a); //根據(jù)規(guī)則1
console.assert(f.a===1); //找到了屬性值
總結(jié):
f.a===f.__proto__.a
===F.prototype.a===1
2. 考察繼承
var G=function(){}; //再來一個構(gòu)造函數(shù)
G.prototype=f; //讓這個構(gòu)造函數(shù)的prototype是剛才那個實(shí)例
var g=new G; //再造一個實(shí)例
console.assert(g.__proto__===G.prototype); //根據(jù)規(guī)則1
console.assert(g.__proto__===f); //根據(jù)剛才的賦值
console.assert(g.a===g.__proto__.a); //根據(jù)規(guī)則2
console.assert(g.a===f.a); //根據(jù)上面的推導(dǎo)
console.assert(g.a===1); //找到了屬性值
總結(jié):
g.a===g.__proto__.a===g.__proto__.__proto__.a
===G.prototype.__proto__.a===f.__proto__.a===F.prototype.a===1
3. 考察只讀性
g.a=2; //為實(shí)例增加屬于自己的屬性
console.assert(g.a===2); //根據(jù)規(guī)則2
console.assert(f.a===1); //不影響其他實(shí)例的查找規(guī)則
結(jié)論:
原型繼承,本質(zhì)上利用了實(shí)例屬性的查找規(guī)則。
參考文獻(xiàn):
《ECMAScript? 2015 Language Specification》——第3頁 4.2.1