このページはコミュニティーの尽力で英語から翻訳されました。MDN Web Docsコミュニティーについてもっと知り、仲間になるにはこちらから。
new.target
Baseline Widely available
This feature is well established and works across many devices and browser versions. It’s been available across browsers since 2017年9月.
new.target はメタプロパティで、関数やコンストラクターがnew 演算子を使用して呼び出されたかどうかを検出することができます。new 演算子を使用して呼び出したコンストラクターや 関数の中では、new.target はnew が呼び出されたコンストラクターまたは関数への参照を返します。通常に呼び出された関数の中では、new.target はundefined になります。
In this article
試してみましょう
function Foo() { if (!new.target) { throw new TypeError("new を付けずに Foo コンストラクターを呼び出すのは不正です"); }}try { Foo();} catch (e) { console.log(e); // 予想される結果: TypeError: new を付けずに Foo コンストラクターを呼び出すのは不正です}構文
new.target値
new.target は、構築可能な関数値またはundefined であることが保証されています。
- クラスのコンストラクター内では、
newが呼び出されたクラスを参照します。これは現在のコンストラクターのサブクラスである可能性があります。サブクラスはsuper()を通じてスーパークラスのコンストラクターを経過的に呼び出すためです。 - 通常の関数では、関数が
newで直接構築された場合、new.targetはその関数自体を参照します。関数がnewなしで呼び出された場合、new.targetはundefinedになります。関数はextendsの基底クラスとして使用されることがあり、その場合new.targetはサブクラスを参照する可能性があります。 - コンストラクター(クラスまたは関数)が
Reflect.construct()経由で呼び出された場合、new.targetはnewTargetとして渡された値(既定はtarget)を参照します。 - アロー関数では、
new.targetは周囲のスコープから継承されます。アロー関数がnew.targetのバインディングを持つ別のクラスや関数内で定義されていない場合、構文エラーが発生します。 - 政敵初期化ブロック内では、
new.targetはundefinedです。
解説
new.target 構文は、キーワードnew とドットとtarget 識別子で構成されています。new は識別子ではなく予約語であるため、これはプロパティアクセサーではなく、特別な式構文です。
new.target メタプロパティは、すべての関数/クラスの本体内で利用できます。関数やクラス の外部でnew.target を使用すると構文エラーになります。
例
>関数呼び出しにおける new.target の使用
通常の関数呼び出しでは (コンストラクター関数の呼び出しとは対照的に)、new.target はundefined になります。これにより、関数がnew 付きでコンストラクターとして呼び出されたかを検出できます。
function Foo() { if (!new.target) { throw new Error("Foo() は new を付けて呼び出さなくてはなりません"); } console.log("Foo が new 付きでインスタンス化されました");}new Foo(); // "Foo が new 付きでインスタンス化されました" を出力Foo(); // "Foo() は new を付けて呼び出さなくてはなりません" 例外が発生コンストラクターにおける new.target
クラスのコンストラクターでは、new.target はnew で直接実行されたコンストラクターを参照します。これは、コンストラクターが親クラスにあり、子コンストラクターから委任された場合も同様です。new.target は、new が呼び出されたクラスを指します。例えば、b がnew B() を使用して初期化された際には、B の名前が表示されます。同様に、a の場合、クラスA の名前が表示されます。
class A { constructor() { console.log(new.target.name); }}class B extends A { constructor() { super(); }}const a = new A(); // Logs "A"const b = new B(); // Logs "B"Reflect.construct() を使用したときの new.target
Reflect.construct() やクラスが登場する以前は、継承を実装する一般的な方法として、this の値を渡し、基底クラスのコンストラクターでそれを変更させる手法が用いられていました。
function Base() { this.name = "Base";}function Extended() { // Base() コンストラクターが、 `new` によって生成される新しいオブジェクト // ではなく、既存の `this` 値に対して動作する唯一の 方法。 Base.call(this); this.otherProperty = "Extended";}Object.setPrototypeOf(Extended.prototype, Base.prototype);Object.setPrototypeOf(Extended, Base);console.log(new Extended()); // Extended { name: 'Base', otherProperty: 'Extended' }ただし、call() およびapply() は実際には関数を「構築」するのではなく「呼び出し」するため、new.target の値はundefined になります。これは、Base() がnew で構築されたかどうかを確認する場合、エラーが発生するか、それ以外にも予期しない動作を引き起こす可能性があるということの意味します。例えば、Map() コンストラクターはnew なしでは呼び出せないため、この方法でMap を拡張することはできません。
すべての組み込みコンストラクターは、new.target.prototype を読み取ることで、新規インスタンスのプロトタイプチェーン全体を直接構築します。したがって、(1)Base がnew で構築され、(2)new.target がBase 自体ではなくサブクラスを指すようにするには、Reflect.construct() を使用する必要があります。
function BetterMap(entries) { // 基底クラスのコンストラクターを呼び出すが、`new.target` をサブクラスに設定する。 // これにより、作成されるインスタンスに正しいプロトタイプチェーンが構築される。 return Reflect.construct(Map, [entries], BetterMap);}BetterMap.prototype.upsert = function (key, actions) { if (this.has(key)) { this.set(key, actions.update(this.get(key))); } else { this.set(key, actions.insert()); }};Object.setPrototypeOf(BetterMap.prototype, Map.prototype);Object.setPrototypeOf(BetterMap, Map);const map = new BetterMap([["a", 1]]);map.upsert("a", { update: (value) => value + 1, insert: () => 1,});console.log(map.get("a")); // 2メモ:実際、Reflect.construct() が存在しないため、 ES6 以前のコードへトランスパイルする際には、組み込みオブジェクトを正しくサブクラス化することができません(Error のサブクラス化など)。
ただし、 ES6 のコードを書く場合は、読み取り可能でエラーの可能性が低いクラスとextends の使用を推奨します。
class BetterMap extends Map { // コンストラクターは既定のコンストラクターのみであるため省略 upsert(key, actions) { if (this.has(key)) { this.set(key, actions.update(this.get(key))); } else { this.set(key, actions.insert()); } }}const map = new BetterMap([["a", 1]]);map.upsert("a", { update: (value) => value + 1, insert: () => 1,});console.log(map.get("a")); // 2仕様書
| Specification |
|---|
| ECMAScript® 2026 Language Specification> # sec-built-in-function-objects> |