ES2015から、実行されたコンストラクタを参照するnew.target
というヤツが追加されました。
コンストラクタ関数がnew
を使わず実行された場合にエラーを出力
function Human (name, food) {
console.log(new.target); // [Function: Human]
this.name = name;
this.food = food;
}
const human = new Human('Jack', '🍔');
console.log(human); // Human { name: 'Jack', food: '🍔' }
上記のプログラムでは、コンストラクタ関数(Human
)を実行し、オブジェクトを生成しています。
new
が使用された場合、new.target
は実行されたコンストラクタ関数を参照します。
暗黙的に空のオブジェクト(this
)を生成し、呼び出し元に生成したオブジェクトを返却する挙動は、new
を使った実行が前提となっています。
ですが、上記のコンストラクタ関数は以下のようにnew
を使わず実行することも可能です。
そうすると、誤った挙動となってしまいます。
function Human (name, food) {
console.log(new.target); // undefined
this.name = name;
this.food = food;
}
const human = Human('Jack', '🍔');
console.log(human); // undefined
new
が使用されなかった場合、new.target
はundefined
になります。
それを利用した以下のような実装をすることで、new
が使われたなかった場合にエラーを出力することができます。
function Human (name, food) {
if (!new.target) {
throw new TypeError('Constructor Human requires "new".');
}
this.name = name;
this.food = food;
}
const human = Human('Jack', '🍔');
throw new TypeError('Constructor Human requires "new".');
^
TypeError: Constructor Human requires "new".
インスタンス化されたクラスを参照する
new.target
は直接実行されたコンストラクタを参照します。
サブクラスを持つ場合、インスタンス化されたのがスーパークラスなのかサブクラスなのかをチェックすることができます。
class Human {
constructor (name, food) {
this.name = name;
this.food = food;
if (new.target === Human) {
console.log(new.target, 'SuperClass🍎');
} else {
console.log(new.target, 'SubClass🍏');
}
}
}
class Mutant extends Human {
constructor (name, food) {
super(name, food);
}
}
const human = new Human('Jack', '🍔'); // [class Human] SuperClass🍎
const mutant = new Mutant('Logan', '🥩'); // [class Mutant extends Human] SubClass🍏