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指向构造函数

以上引用关系可以描述为

构造函数、prototype、实例与原型对象的关系

使用构造函数的目的在于实现继承,达成重用。通过类也可以实现重用

Class

使用Class语法糖可以轻松完成原型的继承

使用不同的方法来创建对象和改变原型链

优点缺点
语法结构{__proto__: ...}高效兼容问题(IE10)
构造函数更加高效、标准需预先定义构造函数;可能会将不需要的方法添加给对象
Object.create()运行运行时优化对象兼容问题(IE8)
Class私有属性、可读、可维护私有属性性能问题;兼容问题
Object.setPrototypeOf(obj, anotherObj)标准、动态修改性能问题、兼容问题(IE8)