在类构造器中使用 new.target
在第三章你已学到了 new.target
,以及在调用函数的方式不同时它的值是如何变动的。你也可以在类构造器中使用 new.target
,来判断类是被如何被调用的。在简单情况下,new.target
就等于本类的构造器函数,正如下例;
class Rectangle {
constructor(length, width) {
console.log(new.target === Rectangle);
this.length = length;
this.width = width;
}
}
// new.target is Rectangle
var obj = new Rectangle(3, 4); // outputs true
此代码说明在 new Rectangle(3, 4)
被调用时,new.target
就等于 Rectangle
。类构造器被调用时不能缺少 new
,因此 new.target
属性就始终会在类构造器内被定义。不过这个值并不总是相同的。研究以下代码:
class Rectangle {
constructor(length, width) {
console.log(new.target === Rectangle);
this.length = length;
this.width = width;
}
}
class Square extends Rectangle {
constructor(length) {
super(length, length)
}
}
// new.target is Square
var obj = new Square(3); // outputs false
Square
调用了 Rectangle
构造器,因此当 Rectangle
构造器被调用时,new.target
等于 Square
。这很重要,因为构造器能根据如何被调用而有不同行为,并且这给了更改这种行为的能力。例如,你可以使用 new.target
来创建一个抽象基类(一种不能被实例化的类),如下:
// abstract base class
class Shape {
constructor() {
if (new.target === Shape) {
throw new Error("This class cannot be instantiated directly.")
}
}
}
class Rectangle extends Shape {
constructor(length, width) {
super();
this.length = length;
this.width = width;
}
}
var x = new Shape(); // throws error
var y = new Rectangle(3, 4); // no error
console.log(y instanceof Shape); // true
此例中的 Shape
类构造器会在 new.target
为 Shape
的时候抛出错误,意味着 new Shape()
永远都会抛出错误。然而,你依然可以将 Shape
用作一个基类,正如 Rectangle
所做的那样。super()
的调用执行了 Shape
构造器,而且 new.target
的值等于 Rectangle
,因此该构造器能够无错误地继续执行。
由于调用类时不能缺少 |