2
1

More than 1 year has passed since last update.

【JavaScript】new.target

Posted at

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.targetundefinedになります。
それを利用した以下のような実装をすることで、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🍏
2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1