[JavaScript] 原型继承的原理

两条规则:

  1. 实例.__proto__ === 构造函数.prototype
  2. 实例.属性 === 如果自身有该属性 ? 实例.属性 : 实例.[__proto__]n次.属性

关于规则2的解释:
查找实例的属性时,先判断自身有没有这个属性,如果有,那么直接获取。
否则,查找它的__proto__有没有这个属性,有的话,就是它,
否则,查找它的__proto__.__proto__有没有这个属性……
如果一直找不到,就是undefined。(此处必有蹊跷……略

测试用例:(测试环境,Chrome 44,Win7)

1. 考察构造函数和实例

var F=function(){};    //构造函数F
F.prototype={};    //先设置构造函数的prototype
var f=new F;    //造一个实例
console.assert(f.__proto__===F.prototype);    //根据规则1

console.assert(f.a===undefined);    //实例还没有这个属性

F.prototype.a=1;    //给prototype增加一个属性
console.assert(f.a===f.__proto__.a);    //根据规则2
console.assert(f.a===F.prototype.a);    //根据规则1
console.assert(f.a===1);    //找到了属性值

总结:

f.a===f.__proto__.a
===F.prototype.a===1

2. 考察继承

var G=function(){};    //再来一个构造函数
G.prototype=f;    //让这个构造函数的prototype是刚才那个实例
var g=new G;    //再造一个实例
console.assert(g.__proto__===G.prototype);    //根据规则1

console.assert(g.__proto__===f);    //根据刚才的赋值
console.assert(g.a===g.__proto__.a);    //根据规则2
console.assert(g.a===f.a);    //根据上面的推导
console.assert(g.a===1);    //找到了属性值

总结:

g.a===g.__proto__.a===g.__proto__.__proto__.a
===G.prototype.__proto__.a===f.__proto__.a===F.prototype.a===1

3. 考察只读性

g.a=2;    //为实例增加属于自己的属性
console.assert(g.a===2);    //根据规则2
console.assert(f.a===1);    //不影响其他实例的查找规则

结论:
原型继承,本质上利用了实例属性的查找规则。

参考文献:
《ECMAScript® 2015 Language Specification》——第3页 4.2.1

点赞