javascript 中通过 es6 class 语法结合 super() 调用父类构造函数,以及子类方法覆盖(override)来实现抽象。具体做法是定义一个基类封装通用逻辑,子类继承该基类并实现特定行为,从而在实例化时自动应用抽象后的结构。

如何定义可复用的基类与子类
使用 extends 关键字让子类继承基类,并在子类的 constructor 中调用 super() 以完成属性初始化。这样基类负责维护公共状态,子类专注于扩展功能。

class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a noise.`);
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name); // 调用父类构造函数
this.breed = breed;
}
speak() {
console.log(`${this.name} barks.`); // 覆盖父类方法
}
}
const dog = new Dog('Rex', 'German Shepherd');
dog.speak(); // 输出: Rex barks.
console.log(dog instanceof Dog); // true
console.log(dog instanceof Animal); // true
运行上述代码,dog.speak() 会输出 Rex barks.,证明子类成功覆盖了父类方法。同时 instanceof 检查显示 dog 既是 Dog 的实例也是 Animal 的实例,验证了继承链的正确性。
如何在子类中访问父类被覆盖的方法
当子类需要复用父类已被覆盖的逻辑时,可以通过 super.methodName() 显式调用父类方法。这在需要扩展而非完全替换原有行为时非常有用。

class Cat extends Animal {
constructor(name, color) {
super(name);
this.color = color;
}
speak() {
super.speak(); // 调用父类 speak 方法
console.log(`${this.name} meows.`); // 追加子类特有行为
}
}
const cat = new Cat('Whiskers', 'White');
cat.speak();
执行 cat.speak() 将依次输出:Whiskers makes a noise.Whiskers meows.
这表明 super.speak() 成功调用了 Animal 类中的原始实现,随后执行了 Cat 类中的额外逻辑。
基于 super() 调用顺序的具体问题
在子类构造函数中,必须在访问 this 之前调用 super(),否则 JavaScript 引擎会抛出 ReferenceError。这是因为子类的 this 上下文依赖于父类构造函数的初始化结果。
class BadExample extends Animal {
constructor(name) {
// this.name = name; // 错误:在 super() 之前使用 this
super(name); // 正确:先调用 super()
this.name = name; // 现在可以安全使用 this
}
}
如果尝试在 super() 之前访问或赋值 this,代码将立即失败。这一规则确保了继承链中对象状态的构建顺序符合预期,避免了未定义行为的产生。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











