ES6 class 中 super 和 new.target 分别有什么作用?
简化版
super 用于在子类中调用父类构造函数或父类方法。派生类构造函数里必须先调用 super(),才能使用 this。
new.target 表示当前构造调用实际使用的构造函数,可用于判断函数是否通过 new 调用,也可用于实现抽象基类限制。
详细版
class Animal {
constructor(name) {
this.name = name;
}
speak() {
return `${this.name} makes noise`;
}
}
class Dog extends Animal {
constructor(name) {
super(name);
}
speak() {
return super.speak() + " and barks";
}
}
new.target:
class Base {
constructor() {
if (new.target === Base) {
throw new Error("Base cannot be constructed directly");
}
}
}
完整版教学
一、super 的两个位置
super 在构造函数里表示调用父类构造函数。
在方法里,super.method() 表示调用父类原型上的方法。
| 位置 | 含义 |
|---|---|
constructor | 调用父类构造函数 |
| 实例方法 | 查找父类原型方法 |
| 静态方法 | 查找父类静态方法 |
constructor -> super(...)
method -> super.method(...)
super不是一个普通变量,它和类的继承关系、方法的内部槽绑定在一起。
二、派生类为什么要先 super
派生类自己的 this 需要由父类构造过程初始化。
class Child extends Parent {
constructor() {
super();
this.ready = true;
}
}
如果在 super() 前访问 this,会抛错。
class Bad extends Parent {
constructor() {
this.x = 1; // ReferenceError
super();
}
}
三、super.method 的 this 仍是当前对象
class Parent {
say() {
return this.name;
}
}
class Child extends Parent {
say() {
return super.say();
}
}
const child = new Child();
child.name = "Ada";
console.log(child.say()); // Ada
super.say() 找的是父类方法,但调用时的 this 仍然是当前实例。
四、静态方法里也能使用 super
class Parent {
static version() {
return 1;
}
}
class Child extends Parent {
static version() {
return super.version() + 1;
}
}
静态上下文中的 super 指向父类构造函数本身,而不是父类原型。
五、new.target 判断真实构造目标
function User() {
console.log(new.target === User);
}
User(); // false 或 undefined 语义
new User(); // true
在类构造函数里,new.target 表示最终被 new 的类。
class Base {
constructor() {
console.log(new.target.name);
}
}
class Child extends Base {}
new Child(); // Child
六、抽象基类限制
JavaScript 没有原生抽象类关键字,但可以用 new.target 做运行时限制。
class Shape {
constructor() {
if (new.target === Shape) {
throw new Error("abstract");
}
}
}
这不是类型系统约束,而是运行时保护。
七、常见误区与追问
- 误区:super.method 里的 this 是父类实例。 实际 this 通常仍是当前子类实例。
- 误区:子类构造函数可以先用 this 再 super。 派生类必须先调用
super()。 - 误区:super 是父类对象的普通引用。 它依赖方法定义位置和内部继承绑定。
- 误区:new.target 只在 class 里能用。 普通函数中也能使用。
- 追问:静态方法中的 super 指向哪里? 指向父类构造函数,用于访问父类静态成员。
- 追问:new.target 能实现什么限制? 可阻止基类被直接实例化,模拟抽象类。
八、加强记忆
记忆图:
Child instance
├─ this -> current instance
├─ super() -> Parent constructor
└─ super.method() -> Parent.prototype.method with current this
回答时抓三点:派生构造函数先 super(),super.method 找父类但 this 仍是当前对象,new.target 表示真实构造目标。