TypeScript 中 super
关键字的底层原理
- 与 JavaScript 原型链的交互:
- 在 JavaScript 中,基于原型链的继承是实现对象间属性和方法共享的重要机制。
super
关键字在类继承的场景下,用于访问和调用父类的属性、方法。
- 当子类实例化时,其
[[Prototype]]
指向父类的实例(通过 Object.setPrototypeOf(subClass.prototype, superClass.prototype)
这样的机制)。super
提供了一种访问父类实例上属性和方法的方式。例如,在子类方法中使用 super.method()
,它会在父类的原型链上查找 method
方法并执行。
- 在构造函数中,
super()
用于调用父类的构造函数。这是必要的,因为子类构造函数在访问 this
之前,必须先调用父类构造函数来初始化继承自父类的属性,确保原型链的正确构建。
- 在装饰器等高级特性下的表现:
- 装饰器与
super
:装饰器可以用来修改类、方法、属性等的行为。当在被装饰的类中使用 super
时,需要注意装饰器可能对原型链和类结构的影响。例如,一个方法装饰器可能会修改方法的执行逻辑,但 super
依然是基于原始的父类原型链来访问父类方法。
- 类装饰器场景:假设一个类装饰器给类添加了一些额外的属性或方法。子类使用
super
时,仍然是访问父类未经装饰器修改前的原型链上的属性和方法。这是因为 super
的解析是基于类定义时的原型链结构,而不是基于运行时被装饰器修改后的类结构。
实际项目开发中利用 super
实现独特功能的场景
- 场景一:重写并增强父类方法
- 实现思路:在很多项目中,可能需要在子类中对父类的某个方法进行扩展。例如,有一个父类
Logger
用于记录简单日志,子类 EnhancedLogger
想要在记录日志的同时发送通知。
- 代码示例:
class Logger {
log(message: string) {
console.log(`Log: ${message}`);
}
}
class EnhancedLogger extends Logger {
log(message: string) {
super.log(message);
// 发送通知逻辑
console.log(`Sending notification for: ${message}`);
}
}
- 在这个例子中,
EnhancedLogger
重写了 log
方法。通过 super.log(message)
先执行父类的日志记录逻辑,然后再添加自己的发送通知逻辑,实现了功能的增强。
- 场景二:复用父类的初始化逻辑
- 实现思路:在创建复杂对象层次结构时,子类可能需要复用父类的构造函数逻辑来初始化一些基础属性。例如,有一个父类
User
包含基本的用户信息属性,子类 AdminUser
除了这些基本属性外还有管理员特有的权限属性。
- 代码示例:
class User {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
class AdminUser extends User {
permissions: string[];
constructor(name: string, age: number, permissions: string[]) {
super(name, age);
this.permissions = permissions;
}
}
- 在
AdminUser
的构造函数中,通过 super(name, age)
调用父类 User
的构造函数来初始化 name
和 age
属性,然后再初始化自己特有的 permissions
属性,避免了在子类构造函数中重复编写父类的初始化逻辑。