new.target屬性
- new是從構造函數生成實例對象的命令。ES6 爲new命令引入了一個new.target屬性,該屬性一般用在構造函數之中,返回new命令作用於的那個構造函數。如果構造函數不是通過new命令或Reflect.construct()調用的,new.target會返回undefined,因此這個屬性可以用來確定構造函數是怎麼調用的。
function Person(name) {
if (new.target !== undefined) {
this.name = name;
} else {
throw new Error('必須使用 new 命令生成實例');
}
}
// 另一種寫法
function Person(name) {
if (new.target === Person) {
this.name = name;
} else {
throw new Error('必須使用 new 命令生成實例');
}
}
var person = new Person('張三'); // 正確
var notAPerson = Person.call(person, '張三'); // 報錯
上面代碼確保構造函數只能通過new命令調用。
- Class 內部調用new.target,返回當前 Class。
class Rectangle {
constructor(length, width) {
console.log(new.target === Rectangle);
this.length = length;
this.width = width;
}
}
var obj = new Rectangle(3, 4); // 輸出 true
- 需要注意的是,子類繼承父類時,new.target會返回子類。
class Rectangle {
constructor(length, width) {
console.log(new.target === Rectangle);
// ...
}
}
class Square extends Rectangle {
constructor(length) {
super(length, width);
}
}
var obj = new Square(3); // 輸出 false
上面代碼中,new.target會返回子類。
- 利用這個特點,可以寫出不能獨立使用、必須繼承後才能使用的類。
class Shape {
constructor() {
if (new.target === Shape) {
throw new Error('本類不能實例化');
}
}
}
class Rectangle extends Shape {
constructor(length, width) {
super();
// ...
}
}
var x = new Shape(); // 報錯
var y = new Rectangle(3, 4); // 正確
上面代碼中,Shape類不能被實例化,只能用於繼承。
注意,在函數外部,使用new.target會報錯。
拓展:
- Object.getPrototypeOf()
Object.getPrototypeOf方法可以用來從子類上獲取父類。
Object.getPrototypeOf(Rectangle) === Shape
// true
因此,可以使用這個方法判斷,一個類是否繼承了另一個類。