このページはコミュニティーの尽力で英語から翻訳されました。MDN Web Docsコミュニティーについてもっと知り、仲間になるにはこちらから。
super
Baseline Widely available
This feature is well established and works across many devices and browser versions. It’s been available across browsers since 2016年3月.
super キーワードは、オブジェクトリテラルやクラスの [[Prototype]] 上のプロパティにアクセスしたり、スーパークラスのコンストラクターを呼び出したりするために使用されます。
super.prop およびsuper[expr] 式は、クラスとオブジェクトリテラルの両方におけるあらゆるメソッド定義で有効です。super(...args) 式はクラスコンストラクター内で有効です。
In this article
試してみましょう
class Foo { constructor(name) { this.name = name; } getNameSeparator() { return "-"; }}class FooBar extends Foo { constructor(name, index) { super(name); this.index = index; } // 呼び出されない getNameSeparator() { return "/"; } getFullName() { return this.name + super.getNameSeparator() + this.index; }}const firstFooBar = new FooBar("foo", 1);console.log(firstFooBar.name);// 予想される結果: "foo"console.log(firstFooBar.getFullName());// 予想される結果: "foo-1"構文
super()super(arg1)super(arg1, arg2)super(arg1, arg2, /* …, */ argN)super.propertyOnParentsuper[expression]解説
super キーワードは、「関数呼び出し」(super(...args))と「プロパティ参照」として(super.prop およびsuper[expr])の 2 つの方法で使用できます。
メモ:super はキーワードであり、これらは特別な構文構造です。super はプロトタイプオブジェクトを指す変数ではありません。super 自体を読み取ろうとするとSyntaxError が発生します。
const child = { myParent() { console.log(super); // SyntaxError: 'super' keyword unexpected here },};派生クラス(extends を使用)のコンストラクター本体では、super キーワードが「関数呼び出し」super(...args) として現れることがあります。これはthis キーワードを使用する前、かつコンストラクターが返す前に呼び出さなければなりません。これは親クラスのコンストラクターを呼び出し、親クラスのパブリックフィールドをバインドします。その後、派生クラスのコンストラクターはさらにthis にアクセスし変更することができます。
「プロパティ参照」 の形で、オブジェクトリテラルやクラスの [[Prototype]] のメソッドやプロパティにアクセスすることができます。クラスの本体では、super の参照は、実行コンテキストがインスタンス作成かクラス初期化かによって、スーパークラスのコンストラクター自体か、コンストラクターのprototype のいずれかになります。詳細は「例」の節を参照してください。
なお、superの参照は、メソッドが呼び出されるオブジェクトではなく、superが宣言されたクラスまたはオブジェクトリテラルによって決定されます。したがって、メソッドのアンバインドや再バインドを行っても、その中のsuperの参照は変わりません(ただし、thisの参照は変わります)。superは、メソッドがクロージャを生成するクラスリテラルまたはオブジェクトリテラルのスコープ内の変数と見なせます(ただし上記の通り、実際には変数ではないことに注意してください)。
super を介してプロパティを設定したときは、そのプロパティは代わりにthis に設定されます。
例
>クラス内での super の使用
このコードスニペットは、クラスの例 (ライブデモ) からとっています。super() を利用することで、Rectangle とSquare のコンストラクターに共通する処理を重複して記述しないようにしています。
class Rectangle { constructor(height, width) { this.name = "Rectangle"; this.height = height; this.width = width; } sayName() { console.log(`Hi, I am a ${this.name}.`); } get area() { return this.height * this.width; } set area(value) { this._area = value; }}class Square extends Rectangle { constructor(length) { // ここでは、親クラスのコンストラクターを呼び出し、指定された長さを // Rectangle の 幅と高さとして渡します。 super(length, length); // メモ: 'this' を使う前に super() を呼び出さなければなりません。 // でないと ReferenceError が発生します。 this.name = "Square"; }}静的メソッドでの super の呼び出し
super は静的メソッドでも呼び出すことができます。
class Rectangle { static logNbSides() { return "I have 4 sides"; }}class Square extends Rectangle { static logDescription() { return `${super.logNbSides()} which are all equal`; }}Square.logDescription(); // 'I have 4 sides which are all equal'クラスフィールド宣言内で super にアクセス
super はクラスフィールドの初期化中にもアクセスすることができます。super の参照は、現在のフィールドがインスタンスフィールドであるか、静的フィールドであるかによって異なります。
class Base { static baseStaticField = 90; baseMethod() { return 10; }}class Extended extends Base { extendedField = super.baseMethod(); // 10 static extendedStaticField = super.baseStaticField; // 90}なお、インスタンスフィールドはコンストラクターのprototype ではなくインスタンス自体に設定されるため、super を使用してスーパークラスのインスタンスフィールドにアクセスすることはできません。
class Base { baseField = 10;}class Extended extends Base { extendedField = super.baseField; // undefined}ここでは、extendedField は 10 ではなくundefined です。baseField はBase.prototype ではなく、Base インスタンスの自分自身で定義されたプロパティであるからです。このコンテキストにおけるsuper は、Extended.prototype の [[Prototype]] であるBase.prototype 上のプロパティのみを見ていきます。
super プロパティを削除するとエラーが発生する
親クラスのプロパティを削除するために、delete 演算子 やsuper.prop、super[expr] を使うことはできません。ReferenceError が発生します。
class Base { foo() {}}class Derived extends Base { delete() { delete super.foo; // this is bad }}new Derived().delete(); // ReferenceError: invalid delete involving 'super'.オブジェクトリテラル内での super.prop の使用
super はオブジェクト初期化子 / リテラル記法内でも使用できます。この例では、 2 つのオブジェクトがメソッドを定義しています。 2 つ目のオブジェクトの中で、super が最初のオブジェクトのメソッドを呼び出しています。これはObject.setPrototypeOf() の助けで動作し、これはobj2 のプロトタイプをobj1 に設定するので、super はmethod1 をobj1 上で見つけることができます。
const obj1 = { method1() { console.log("method 1"); },};const obj2 = { method2() { super.method1(); },};Object.setPrototypeOf(obj2, obj1);obj2.method2(); // "method 1" を出力super.prop を読み取るメソッドは、他のオブジェクトにバインドされても動作が変わらない
super.x へのアクセスはReflect.get(Object.getPrototypeOf(objectLiteral), "x", this) のように動作します。これは、プロパティが常にオブジェクトリテラル/クラス宣言のプロトタイプ上で検索されるということであり、メソッドのアンバインドや再バインドを行ってもsuper の参照は変更されません。
class Base { baseGetX() { return 1; }}class Extended extends Base { getX() { return super.baseGetX(); }}const e = new Extended();console.log(e.getX()); // 1const { getX } = e;console.log(getX()); // 1オブジェクトリテラルでも同じことになります。
const parent1 = { prop: 1 };const parent2 = { prop: 2 };const child = { myParent() { console.log(super.prop); },};Object.setPrototypeOf(child, parent1);child.myParent(); // "1" と出力const myParent = child.myParent;myParent(); // ここでも "1" と出力const anotherChild = { __proto__: parent2, myParent };anotherChild.myParent(); // ここでも "1" と出力継承チェーン全体をリセットすることでのみ、super の参照が変更されます。
class Base { baseGetX() { return 1; } static staticBaseGetX() { return 3; }}class AnotherBase { baseGetX() { return 2; } static staticBaseGetX() { return 4; }}class Extended extends Base { getX() { return super.baseGetX(); } static staticGetX() { return super.staticBaseGetX(); }}const e = new Extended();// インスタンス継承のリセットObject.setPrototypeOf(Extended.prototype, AnotherBase.prototype);console.log(e.getX()); // プロトタイプチェーンが変更されたため、"1" ではなく "2" をログ出力console.log(Extended.staticGetX()); // ここでも "3" とログ出力します。静的部分をまだ変更していないため// 静的継承のリセットObject.setPrototypeOf(Extended, AnotherBase);console.log(Extended.staticGetX()); // "4" とログ出力されるようになるsuper からのメソッド呼び出し
関数としてsuper.prop を呼び出した場合、prop 関数内のthis 値は現在のthis であり、super が指すオブジェクトにはなりません。例えば、super.getName() を呼び出すと、コード上はBase.getName() と同等に見えますが、"Extended" を出力します。
class Base { static getName() { console.log(this.name); }}class Extended extends Base { static getName() { super.getName(); }}Extended.getName(); // "Extended" と出力これは特に、プライベート静的要素を操作する際に重要です。
super.prop に設定すると、代わりに this のプロパティに設定される
super のプロパティにsuper.x = 1 のように設定すると、Reflect.set(Object.getPrototypeOf(objectLiteral), "x", 1, this) と同様に動作します。これはsuper を単に「プロトタイプオブジェクトへの参照」と理解するだけでは不十分なケースの一つです。実際にはthis のプロパティを設定するからです。
class A {}class B extends A { setX() { super.x = 1; }}const b = new B();b.setX();console.log(b); // B { x: 1 }console.log(Object.hasOwn(b, "x")); // truesuper.x = 1 はA.prototype 上のx のプロパティ記述子を見ますが(そこに定義されたセッターを呼び出す)、this の値はthis (このコンテキストではb)に設定されます。Reflect.set には、target とreceiver が異なる場合の詳しい説明があります。
これは、super.prop を取得するメソッドは通常this コンテキストの変更の影響を受けない一方で、super.prop を設定するメソッドは影響を受けるということです。
/* 上記と同じ宣言を再利用 */const b2 = new B();b2.setX.call(null); // TypeError: Cannot assign to read only property 'x' of object 'null'ただし、super.x = 1 は依然としてプロトタイプオブジェクトのプロパティ記述子を参照するので、書き込み不可のプロパティは上書きできず、セッターが呼び出されます。
class X { constructor() { // 書き込み不可のプロパティを作成 Object.defineProperty(this, "prop", { configurable: true, writable: false, value: 1, }); }}class Y extends X { constructor() { super(); } foo() { super.prop = 2; // 値を上書きできない }}const y = new Y();y.foo(); // TypeError: "prop" は読み取り専用console.log(y.prop); // 1仕様書
| Specification |
|---|
| ECMAScript® 2026 Language Specification> # sec-super-keyword> |