JavaScript | ES6+ 文法:クラス構文 – メソッド定義

JavaScript JavaScript
スポンサーリンク

クラスの「メソッド定義」とは何か

クラスのメソッドは、「そのクラスから作ったインスタンスができる“動き(振る舞い)”を表す関数」です。
class の中に書く関数が、インスタンスから user.greet() のように呼べるメソッドになります。

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

  greet() {
    console.log(`こんにちは、${this.name} です`);
  }
}

const u = new User("Alice");
u.greet(); // こんにちは、Alice です
JavaScript

ここが重要です。
「データ」は this.name のようなプロパティで持ち、
「そのデータをどう使うか」はメソッドで表現します。
クラスは「データ(プロパティ)+振る舞い(メソッド)」のセットだとイメージしてください。

クラスのメソッド定義の基本構文

function は書かない(メソッド定義省略)

オブジェクトリテラルのときと同じで、クラスの中では function を書きません。

class Counter {
  constructor(initial = 0) {
    this.value = initial;
  }

  increment() {
    this.value++;
  }

  show() {
    console.log(this.value);
  }
}

const c = new Counter(10);
c.increment();
c.show(); // 11
JavaScript

increment()show() の部分は、実際には

increment: function () { ... }
JavaScript

という書き方の「短縮形」です。
メソッド名(引数) { ... } と書いたら、それは「メソッド」として定義されると覚えてください。

メソッドの中の this は「そのインスタンス」を指す

メソッド定義で一番大事なのが this の意味です。

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

  greet() {
    console.log(`Hi, ${this.name}`);
  }
}

const u1 = new User("Alice");
const u2 = new User("Bob");

u1.greet(); // Hi, Alice
u2.greet(); // Hi, Bob
JavaScript

u1.greet() が呼ばれているとき、greet の中の thisu1 を指します。
u2.greet() のときは thisu2 です。

ここが重要です。
「メソッドの中の this は、呼び出し元のインスタンス」
これが分かると、「インスタンスごとに違う動き」が自然に書けるようになります。

インスタンスメソッドと static メソッドの違い

インスタンスメソッド:インスタンスに対する操作

普通のメソッドは「インスタンスメソッド」です。
インスタンスから呼び出します。

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

  greet() {
    console.log(`Hi, ${this.name}`);
  }
}

const u = new User("Alice");
u.greet(); // インスタンスメソッド
JavaScript

インスタンスメソッドの中で this を使うと、そのインスタンスのプロパティにアクセスできます。

static メソッド:クラス自体に対する操作

static を付けたメソッドは、「インスタンスではなくクラス自身から呼ぶメソッド」です。

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

  describe() {
    console.log(`${this.name} (${this.admin ? "管理者" : "一般"})`);
  }

  static createAdmin(name) {
    return new User(name, true);
  }
}

const u1 = new User("Alice");
const u2 = User.createAdmin("Bob"); // static メソッド

u1.describe(); // Alice (一般)
u2.describe(); // Bob (管理者)
JavaScript

インスタンスメソッドは u1.describe() のようにインスタンスから呼びますが、
static メソッドは User.createAdmin() のようにクラス名から呼びます。

ここが重要です。
インスタンスごとの状態に依存する処理 → インスタンスメソッド
「インスタンスを作る便利関数」「クラス全体に関する処理」 → static メソッド
と役割分担すると設計がきれいになります。

メソッドとアロー関数の違い(this の挙動に注意)

クラスのメソッドは基本「通常メソッド構文」を使う

クラスの中では、アロー関数でメソッドを書くことも技術的にはできますが、
初心者のうちは method() { ... } の形に統一するほうが安全です。

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

  show() {
    console.log(this.value);
  }
}
JavaScript

アロー関数で書くとこうなります。

class Risky {
  value = 1;

  show = () => {
    console.log(this.value);
  }
}
JavaScript

こちらは「クラスフィールドにアロー関数を代入している」形で、
内部的な動きや this の扱いが少し違います。

ここが重要です。
クラスのメソッドとして this を素直に使いたいなら、show() { ... } の形を使う
アロー関数は、this を固定したい特殊なケースにだけ使う、と覚えた方が混乱しません。

メソッドを変数に取り出したときの this

これはクラスに限らずですが、メソッドを変数に代入して呼ぶと、this が変わります。

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

  greet() {
    console.log(this.name);
  }
}

const u = new User("Alice");
u.greet(); // this は u

const fn = u.greet;
fn(); // this が u ではなくなる(undefined になることが多い)
JavaScript

このような場合、bind で this を固定したり、アロー関数フィールドを使ったりするテクニックもありますが、
初心者のうちは「基本は u.greet() の形で呼ぶ」と覚えておけば十分です。

メソッドの役割を意識した設計(重要な考え方)

「何をプロパティにして、何をメソッドにするか」

クラス設計で大事なのは、「プロパティ(状態)とメソッド(振る舞い)」をきちんと分けることです。

例えば銀行口座を表すクラスなら:

class BankAccount {
  constructor(owner, balance = 0) {
    this.owner = owner;   // プロパティ(状態)
    this.balance = balance;
  }

  deposit(amount) {      // メソッド(振る舞い)
    this.balance += amount;
  }

  withdraw(amount) {
    if (this.balance >= amount) {
      this.balance -= amount;
      return true;
    }
    return false;
  }

  show() {
    console.log(`${this.owner} の残高: ${this.balance}`);
  }
}
JavaScript

ownerbalance は「その口座が持つ情報」なのでプロパティ、
depositwithdraw は「その口座ができる操作」なのでメソッドです。

ここが重要です。
“名詞っぽいもの”はプロパティ、“動詞っぽいもの”はメソッド
というざっくりした基準で考えると、初心者にも分かりやすく整理できます。

メソッドは「そのクラスの世界のルール」を表現する

先ほどの withdraw は、「残高が足りないときは引き出せない」というルールを中に持っています。

withdraw(amount) {
  if (this.balance >= amount) {
    this.balance -= amount;
    return true;
  }
  return false;
}
JavaScript

もしこれをクラスの外で毎回書くと、あちこちにルールが分散してバグの元になります。

// 悪い例:クラスの外で勝手に balance をいじる
if (account.balance >= 1000) {
  account.balance -= 1000;
}
JavaScript

ここが重要です。
「そのクラスのものに関するルールは、そのクラスのメソッドの中に閉じ込める」
これができていると、クラスのメソッド定義が「世界のルール集」になり、コードが理解しやすくなります。

継承とメソッドのオーバーライド

親クラスのメソッドを引き継ぐ

extends を使うと、親クラスのメソッドをそのまま子クラスでも使えます。

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

  speak() {
    console.log(`${this.name} が何かを喋った`);
  }
}

class Dog extends Animal {
  bark() {
    console.log(`${this.name}「ワン!」`);
  }
}

const d = new Dog("ポチ");
d.speak(); // 親クラスのメソッド
d.bark();  // 子クラス独自のメソッド
JavaScript

親のメソッドを上書き(オーバーライド)する

子クラスで同じ名前のメソッドを定義すると、親のメソッドを「上書き」できます。

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

  speak() {
    console.log(`${this.name} が何かを喋った`);
  }
}

class Dog extends Animal {
  speak() {
    console.log(`${this.name}「ワン!」`);
  }
}

const d = new Dog("ポチ");
d.speak(); // ポチ「ワン!」(親ではなく子の speak が使われる)
JavaScript

親の処理も呼びたいときは super を使います。

class Dog extends Animal {
  speak() {
    super.speak();                // 親の speak
    console.log(`${this.name} はしっぽを振っている`);
  }
}
JavaScript

ここが重要です。
子クラスのメソッド定義は、「共通の振る舞いを変えたり、追加したりする場所」
継承とメソッド定義を組み合わせると、「似ているけど少し違うものたち」をうまく表現できます。

例題でメソッド定義に慣れる

例1:ユーザー操作をメソッドでまとめる

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

  login() {
    this.loginCount++;
    console.log(`${this.name} がログイン (${this.loginCount} 回目)`);
  }

  rename(newName) {
    this.name = newName;
  }
}

const u = new User("Alice");
u.login();
u.rename("Bob");
u.login();
JavaScript

例2:図形クラスのメソッド(面積計算など)

class Rectangle {
  constructor(width, height) {
    this.width = width;
    this.height = height;
  }

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

  describe() {
    console.log(`幅: ${this.width}, 高さ: ${this.height}, 面積: ${this.area()}`);
  }
}

const r = new Rectangle(10, 5);
r.describe();
JavaScript

例3:継承+メソッドオーバーライド

class Shape {
  area() {
    return 0;
  }

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

class Circle extends Shape {
  constructor(radius) {
    super();
    this.radius = radius;
  }

  area() {
    return Math.PI * this.radius * this.radius;
  }
}

const c = new Circle(3);
c.describe();
JavaScript

Shapedescribearea() を呼んでいますが、
Circlearea をオーバーライドしているので、
c.describe() では円の面積が計算されます。

まとめ

クラスのメソッド定義の核心は、
「そのクラスのインスタンスが“何ができるか”を、メソッド名() { ... } の形で列挙する」 ことです。

押さえておきたいポイントを整理すると、

  • クラスのメソッドは メソッド名(引数) { ... } と書く(function は不要)
  • メソッド内の this は「そのメソッドを呼び出したインスタンス」を指す
  • 状態(データ)はプロパティ、操作(振る舞い)はメソッド、という役割分担で考える
  • インスタンスごとの操作は普通のメソッド、クラス全体に関する操作や生成用ユーティリティは static メソッド
  • 継承時には、親クラスのメソッドをそのまま使ったり、オーバーライドして振る舞いを変えたりできる
  • アロー関数は this の挙動が違うので、初心者のうちはメソッド定義には使わない方が安全

まずは小さなクラスを作って、
「どんなメソッドがあると、このクラスは“気持ちよく”使えるか」を考えながらメソッドを増やしてみてください。
その感覚が育ってくると、クラス設計そのものが面白くなってきます。

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