1. extends的作用与基本语义
核心原理
在 ES6 中,extends 用于定义一个子类继承自一个父类。实现原理包括设置子类的原型链为父类的原型的一个副本,以及让子类的构造器在实例化时能够访问父类的方法与属性。通过这种方式,子类实例能够获得父类的实例方法。
具体地,语法上 extends 会把 Child.prototype 设为 Object.create(Parent.prototype),并把 Child.prototype.constructor 指回 Child;这使得 instanceof、isPrototypeOf 等原型链相关操作生效。
通过拥有 super,派生类可以调用父类的构造器和方法,确保初始化逻辑可以复用。若在派生类的构造函数中未调用 super(),将会抛出错误,且 this 尚未可用。

class Animal {constructor(name) {this.name = name;}speak() {return `${this.name} makes a noise.`;}
}
class Dog extends Animal {constructor(name) {super(name);this.isPet = true;}speak() {return `${this.name} barks.`;}
}
const d = new Dog('Rex');
console.log(d.speak()); // Rex barks.
与普通对象继承的区别
与直接通过对象复制来实现“继承”不同,extends 会把父类放在原型链的正确位置,使得方法查找沿着原型链向上进行。这样不仅在语义上清晰,也兼具运行时的性能优势。
此外,extends 支持对内建类型、自定义类和混合类的扩展,提供统一的继承模型。通过 super 可以访问父类的方法实现重用。下面示例展示一个简单的子类覆盖父类方法的方式。
2. 常见使用场景与代码示例
典型的模型/组件式继承
在大型应用中,extends 常用于实现模型、控件或服务的层次结构。通过定义一个通用父类 BaseModel,子类就能复用公共行为,比如序列化、校验、日志等。
在子类中可以覆写父类的方法,同时通过 super 调用父类的默认实现,以实现行为的扩展。
class BaseModel {serialize() {return JSON.stringify(this);}validate() {// 基础校验return true;}
}
class UserModel extends BaseModel {constructor(id, name) {super();this.id = id;this.name = name;}validate() {// 调用父类的校验并扩展return super.validate() && this.id != null && !!this.name;}
}
const user = new UserModel(1, 'Alice');
console.log(user.serialize()); // {"id":1,"name":"Alice"}
console.log(user.validate()); // true
对内建类型的扩展示例
JavaScript 的 Array、Map 等内建类型也可以被继承。对内建类型的扩展需要注意构造器中调用 super,并且有些方法的行为在子类中可能需要重新实现或覆盖。
class MyArray extends Array {constructor(...args) {super(...args);}first() {return this[0];}
}
const arr = new MyArray(1, 2, 3);
arr.push(4);
console.log(arr.length); // 4
console.log(arr.first()); // 1
在 UI 组件或自定义控件中的使用场景
对于需要在现有组件体系上实现扩展的场景,extends 提供了清晰的语义,例如自定义控件继承自基本控件,以复用事件处理、生命周期等能力。
在实际开发中,确保 构造器 调用了 super,并避免在子类中直接操作未初始化的父类成员。下面是一个简化的自定义控件示例。
class Widget {constructor(el) {this.el = el;this.init();}init() {// 初始化}
}
class Button extends Widget {constructor(el, label) {super(el);this.label = label;}click() {console.log(`Button "${this.label}" clicked`);}
}
3. 继承中的注意事项与性能要点
正确使用 super 与构造流程
核心要点包括:派生类构造器必须在使用 this 之前调用 super();调用顺序决定了初始化顺序,错误的顺序会抛出错误。
通过 super 可以访问父类的实例方法和静态方法,使得代码复用更高效。
class Parent {static info() { return 'parent'; }constructor() { this.value = 42; }getValue() { return this.value; }
}
class Child extends Parent {constructor() {super();// 这里可以继续自定义初始化}show() { return super.getValue(); }
}
console.log(Child.prototype instanceof Parent); // true
console.log(new Child().show()); // 42
继承的性能与最佳实践
实现继承并非越多越好,应结合组合优先于继承 的设计原则,避免过深的继承树导致耦合难以维护。
跨库或框架穿透 时,注意对原型链的影响,尽量在可控范围内进行扩展,避免破坏现有的类型猜测和 instanceof 行为。
兼容性方面,ES6 class extends 在现代浏览器和 Node.js 环境中得到良好支持;在旧环境中需要使用诸如 Babel 的转译工具进行编译以确保兼容性。


