标准答案

  1. class 是基于原型链的语法层,并不是新的继承模型。class 里的实例方法会定义在构造函数的 prototype 上,实例通过原型链访问这些方法。
  2. constructor 是创建实例时执行的构造函数。class 必须通过 new 调用,不能像普通函数一样直接调用;class 内部默认运行在严格模式下。
  3. extends 用来建立子类和父类的继承关系。子类 constructor 中必须先调用 super(),才能访问 this,因为 super() 会执行父类构造逻辑并初始化实例。
  4. static 定义的是类本身的方法或属性,不属于实例。实例不能直接访问 static 方法;静态方法里可以通过 super 调用父类静态方法。

题目解析

class 更像是把构造函数、prototype 方法和继承关系包装成更清晰的语法。理解 class 时仍然要回到原型链:实例方法不复制到每个实例上,而是挂在 prototype 上共享。

extends 不只连接实例原型链,也会连接子类构造函数和父类构造函数之间的继承关系。因此子类既能继承实例方法,也能通过静态继承使用父类静态成员。

super 有两个常见位置:在子类 constructor 中调用父类构造函数;在实例方法中调用父类原型方法。静态方法里的 super 则指向父类本身。

class 方法默认不可枚举,这和直接给构造函数 prototype 赋值有差异。理解这些细节有助于解释 Object.keys、for...in 为什么看不到 class 方法。

代码示例

下面例子展示 class 方法仍然位于 prototype 上,static 方法属于类本身。

JavaScript
class Animal {
  constructor(name) {
    this.name = name
  }

  speak() {
    return this.name + ' makes a noise'
  }

  static category() {
    return 'life'
  }
}

class Dog extends Animal {
  speak() {
    return super.speak() + ', and barks'
  }
}

const dog = new Dog('Lucky')
dog.speak()
Dog.category()

Object.getPrototypeOf(dog) === Dog.prototype // true
Dog.prototype.speak === dog.__proto__.speak // true

常见误区

  • 误以为 class 彻底脱离原型链。
  • 子类 constructor 中在 super() 前访问 this。
  • 把 static 方法当成实例方法调用。

作者信息