JavaScript的原型链
原型链与继承
javascript.infoMDN优先参看MDN标准
原型与原型链
JavaScript中每个对象都有隐藏属性 [[Prototype]]指向另一个对象或null。当访问对象的一个属性时,会先查找自身是否含有该属性,否则查找[[Prototype]]对象是否含有,直到Object.[[Prototype]],Object的原型对象指向null
被引用的对象称为原对象的原型,这样自下而上的查找机制构成了原型链
如果原型对象拥有的属性或方法,会通过这种引用方式被对象继承
关于__proto__
{ __proto__: ... }与Object.__proto__ 不同
前者可以为对象指定它的原型;但后者是浏览器对[[Prototype]]属性访问器的实现,本质是该属性的setter和getter
现今该属性可以使用Object.getPrototypeOf()、Object.setPrototypeOf()、Reflect.getPrototypeOf()、Reflect.setPrototypeOf()进行访问和修改
继承
- 继承“方法”——JavaScript中没有“方法”,任何函数都可以作为属性定义在对象上,原型对象的方法也可在对象上调用,但
this永远指向调用它的对象(即原对象调用方法时this指向原对象而非原型对象)。 - 继承属性——属性遮蔽:如果对象拥有某个属性,且其原型对象也拥有该属性(指同名属性),这时会采用对象的属性。
重用及继承
需要注意的是,并不应该操作构造函数的prototype对原生代码进行覆写。这种行为可能常见于面试题或面向面试题的教程(如javascript.info)
同理,使用该方法对程序中已有构造函数进行功能拓展也不合理
构造函数
该部分可参照MDN以下解释仅为概念关系的描述
构造函数的prototype指向原型对象,在使用new时自动为调用被构造的对象添加[[Prototype]],该属性指向原型对象。而对象的constructor指向构造函数
以上引用关系可以描述为

使用构造函数的目的在于实现继承,达成重用。通过类也可以实现重用
Class
使用Class语法糖可以轻松完成原型的继承
使用不同的方法来创建对象和改变原型链
| 优点 | 缺点 | |
|---|---|---|
语法结构{__proto__: ...} | 高效 | 兼容问题(IE10) |
| 构造函数 | 更加高效、标准 | 需预先定义构造函数;可能会将不需要的方法添加给对象 |
Object.create() | 运行运行时优化对象 | 兼容问题(IE8) |
Class | 私有属性、可读、可维护 | 私有属性性能问题;兼容问题 |
Object.setPrototypeOf(obj, anotherObj) | 标准、动态修改 | 性能问题、兼容问题(IE8) |