JavaScript | ES6+ 文法:クラス構文 – super

JavaScript JavaScript
スポンサーリンク

super とは何か(まずイメージから)

super は、クラスの継承で使う「親クラスへの入り口」です。
具体的には次の2つの役割があります。

  • 親クラスの constructor を呼ぶ
  • 親クラスのメソッドを呼ぶ

「子どものクラスから、“親のやっていること”を呼び出すためのキーワード」と思ってください。

class Parent {
  constructor(name) {
    this.name = name;
  }

  greet() {
    console.log(`親の greet: ${this.name}`);
  }
}

class Child extends Parent {
  constructor(name, age) {
    super(name);        // 親の constructor を呼ぶ
    this.age = age;
  }

  greet() {
    super.greet();      // 親の greet を呼ぶ
    console.log(`子の greet: ${this.age} 歳`);
  }
}

const c = new Child("Alice", 20);
c.greet();
// 親の greet: Alice
// 子の greet: 20 歳
JavaScript

ここが重要です。
extends を使うなら、「super はほぼ必ずセットで出てくる」と思ってください。
特に constructor の中の super(...) は、継承クラスでは超重要です。

constructor の中での super(最重要ポイント)

子クラスの constructor では、最初に super(…) が必須

親クラスを継承したクラスで constructor を書くときは、
必ず一番最初に super(...) を呼ばなければいけません。

class Animal {
  constructor(name) {
    this.name = name;
  }
}

class Dog extends Animal {
  constructor(name, breed) {
    super(name);      // 親の constructor(name) を呼ぶ → this.name をセット
    this.breed = breed;
  }
}

const d = new Dog("ポチ", "柴犬");
console.log(d.name);  // ポチ
console.log(d.breed); // 柴犬
JavaScript

もし super(name) を呼ぶ前に this に触ると、エラーになります。

class BadDog extends Animal {
  constructor(name, breed) {
    // this.breed = breed; // ここで触るとエラー
    super(name);
    this.breed = breed;    // これは OK
  }
}
JavaScript

ここが重要です。
子クラスの constructor では、「親の準備が終わる前に this を触ってはいけない」というルールがあります。
そのため、「extends しているクラスに constructor を書いたら、まず super(...)」と反射的に書けるようにしておくと楽です。

super(…) の中身は「親 constructor への引数」

super(...) に渡した値は、そのまま親クラスの constructor に渡されます。

class Parent {
  constructor(a, b) {
    this.a = a;
    this.b = b;
  }
}

class Child extends Parent {
  constructor(a, b, c) {
    super(a, b); // Parent の constructor(a, b) を呼ぶ
    this.c = c;
  }
}

const ch = new Child(1, 2, 3);
console.log(ch); // { a: 1, b: 2, c: 3 }
JavaScript

親の constructor の引数が変わったら、それに合わせて super(...) の呼び方も変える必要があります。

親の constructor そのままで良いなら、子に constructor は不要

子クラスで特別な初期化をしたくない場合は、constructor 自体を書かなくてOKです。

class Animal {
  constructor(name) {
    this.name = name;
  }
}

class Dog extends Animal {
  // constructor を書かなければ、
  // constructor(...args) { super(...args); } があるイメージ
}

const d = new Dog("ポチ");
console.log(d.name); // ポチ
JavaScript

constructor を書くのは、「親の初期化に加えて、自分独自の初期化が必要なときだけ」です。

メソッドの中での super(親メソッドの呼び出し)

親メソッドを「上書きしつつ、一部だけ変えたい」場合

子クラスで同じ名前のメソッドを定義すると、親のメソッドを「オーバーライド(上書き)」できます。
このとき、親の処理も使いたいなら super.メソッド名() を呼びます。

class Logger {
  log(message) {
    console.log("LOG:", message);
  }
}

class TimestampLogger extends Logger {
  log(message) {
    const now = new Date().toISOString();
    super.log(`${now} - ${message}`); // 親の log を利用
  }
}

const logger = new TimestampLogger();
logger.log("Hello");
// LOG: 2025-12-20T...Z - Hello
JavaScript

ここが重要です。
「共通の基本処理は親に残し、子では前後に独自の処理を足す」
そのための接着剤として super.method() を使う、という感覚です。

メソッドの中の super の正体

ざっくりいうと、メソッド内での super.xxx() は「親クラスの prototype 上のメソッドを呼んでいる」と考えてOKです。

class Parent {
  talk() {
    console.log("親です");
  }
}

class Child extends Parent {
  talk() {
    super.talk();      // Parent.prototype.talk.call(this) とほぼ同じ
    console.log("子です");
  }
}
JavaScript

super を通じて親のメソッドを呼ぶときも、this は「今のインスタンス」のままです。
つまり、親メソッドの中からも、子インスタンスのプロパティにアクセスできます。

constructor での super と メソッドでの super の違い

constructor 内の super は「関数呼び出し」

class Parent {
  constructor(name) {
    this.name = name;
  }
}

class Child extends Parent {
  constructor(name, age) {
    super(name); // 関数呼び出し(親 constructor)
    this.age = age;
  }
}
JavaScript

ここでは super(...) だけで使い、「親 constructor を呼ぶ」特別な構文です。

メソッド内の super は「親のメソッドへの参照」

class Parent {
  greet() {
    console.log("親の greet");
  }
}

class Child extends Parent {
  greet() {
    super.greet(); // 親メソッドの呼び出し
    console.log("子の greet");
  }
}
JavaScript

ここでは super.greet() のように、「super.メンバー名」の形で使います。

ここが重要です。
constructor の中では super(...)(関数呼び出し)、
普通のメソッドの中では super.xxx(...)(親のメソッドやプロパティ参照)
というように、使い方が微妙に違うので混同しないようにしてください。

よくあるつまづきポイントと注意点(ここを押さえると楽)

子クラスの constructor で super を忘れる

一番多いミスがこれです。

class Parent {
  constructor() {
    this.value = 1;
  }
}

class Child extends Parent {
  constructor() {
    // super(); を忘れると…
    this.value = 2; // ここでエラー
  }
}
JavaScript

「派生クラスの constructor では super() を先に呼ぶ必要があります」
というエラーに出会うことになります。
対策はただひとつ、
extends したクラスに constructor を書いたら、最初の行に必ず super(...) を書く」。
慣れるまでは、これを機械的ルールにしてしまうのがおすすめです。

親クラスが constructor を持たなくても super() は必要

親クラスが constructor を定義していなくても、
子クラスの constructor では super() を呼ばないといけません。

class Parent {
  // constructor は定義していない(=暗黙の constructor() {})
}

class Child extends Parent {
  constructor() {
    super(); // それでも必須
    this.value = 1;
  }
}
JavaScript

「親に constructor がないから super いらないでしょ?」と思いがちですが、
仕様として「extends しているクラスの constructor では super() が必須」です。

static メソッドからの super の利用(存在だけ知っておけばOK)

少し進んだ使い方として、static メソッドの中でも super が使えます。

class Parent {
  static whoAmI() {
    console.log("Parent");
  }
}

class Child extends Parent {
  static whoAmI() {
    super.whoAmI(); // Parent.whoAmI()
    console.log("Child");
  }
}

Child.whoAmI();
// Parent
// Child
JavaScript

初心者のうちは、「インスタンスメソッドや constructor で super を使う」ケースをしっかり押さえておけば十分です。
static での super は、「そういうのもある」くらいの理解でOKです。

例題で super の感覚を固める

例1:ユーザーと管理者で共通部分は親にまとめる

class User {
  constructor(name) {
    this.name = name;
  }

  describe() {
    console.log(`${this.name}(一般ユーザー)`);
  }
}

class Admin extends User {
  constructor(name, permissions = []) {
    super(name); // User の constructor(name) を呼ぶ
    this.permissions = permissions;
  }

  describe() {
    super.describe(); // 親の describe も呼ぶ
    console.log(`権限: ${this.permissions.join(", ")}`);
  }
}

const a = new Admin("Alice", ["READ", "WRITE"]);
a.describe();
// Alice(一般ユーザー)
// 権限: READ, WRITE
JavaScript

例2:図形クラスで共通処理+具体クラスの実装

class Shape {
  area() {
    return 0;
  }

  describe() {
    console.log(`面積: ${this.area()}`);
  }
}

class Rectangle extends Shape {
  constructor(width, height) {
    super(); // 親に特別な初期化はないがルールとして呼ぶ
    this.width = width;
    this.height = height;
  }

  area() {
    return this.width * this.height;
  }
}

const r = new Rectangle(10, 5);
r.describe(); // 面積: 50
JavaScript

describe は親に1つだけ定義し、area を子がオーバーライドしています。
ここでは super.describe() を使っていませんが、
「親に共通処理を置いて、子で要点だけ変える」という継承設計の雰囲気が掴めると思います。

例3:ログ出力の前後で親メソッド+追加情報

class Logger {
  log(message) {
    console.log(message);
  }
}

class DebugLogger extends Logger {
  log(message) {
    const time = new Date().toISOString();
    super.log(`[${time}] ${message}`); // 親の log を再利用
  }
}

const logger = new DebugLogger();
logger.log("処理開始");
// [2025-12-20T...] 処理開始
JavaScript

まとめ

super の核心は、
「継承関係の中で、“親クラスの constructor やメソッド” を呼び出すためのキーワード」 であることです。

特に大事なのは次のポイントです。

  • constructor 内の super(...) は「親の constructor(…) を呼ぶ」特別な構文
    子クラスの constructor では、必ず最初に呼ばなければならない
  • メソッド内の super.method(...) は「親クラスの同名メソッドを呼ぶ」
    親の処理+子の追加処理、という形を作るのに便利
  • 親の constructor をそのまま使うだけなら、子クラスに constructor は書かなくて良い
  • extends を使うなら、「super はセットで覚える」くらいの重要な存在

まずは、親クラスと子クラスを自分で1セット作ってみて、
「親に共通処理」「子で差分」「子の constructor で super」を何度か手で書いてみてください。
super が“必須な場面”と“便利な場面”が、だんだん感覚として分かってきます。

タイトルとURLをコピーしました