外观
JavaScript 怎么实现继承?
现在用 class extends。它背后仍是原型链:子类原型指向父类原型,子类构造函数的原型指向父类构造函数。派生类的构造函数必须先 super,才能用 this。
原理
ES6 之前常见的是寄生组合继承:子构造函数里 Parent.call(this, ...args) 继承实例属性,再用 Object.create(Parent.prototype) 继承方法,避免调用两次父构造函数。
js
function Child(name, age) {
Parent.call(this, name)
this.age = age
}
Child.prototype = Object.create(Parent.prototype)
Child.prototype.constructor = Child只把 Child.prototype = Parent.prototype 会让两边共享同一个原型对象,子类加方法会污染父类。Child.prototype = new Parent() 能用,但会多执行一次父构造函数,还可能带上不该有的实例字段。
静态方法跟着构造函数的原型链走,所以 extends 之后 Child 也能找到 Parent 上的静态方法。
追问
组合继承为什么过时了?
Child.prototype = new Parent() 加上 Parent.call(this) 会把父构造函数跑两遍。寄生组合只 call 一次,原型用 Object.create。class 把这些细节收进语法。
能不能继承内建类?
class MyArray extends Array 可以。ES5 那套手动改原型,对 Array、Date、Map 经常不完整,因为它们的内部槽不是普通属性。
易错点
- 忘记补
constructor,instanceof仍可能为真,但instance.constructor会指向父类。 - 派生类在
super()之前读this会抛错。 - 原型上的方法被所有实例共享,不要在原型上放会被改掉的数据。