Skip to content

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 会抛错。
  • 原型上的方法被所有实例共享,不要在原型上放会被改掉的数据。

相关 ​