5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

オフグリッドAdvent Calendar 2024

Day 7

オブジェクト指向を深掘り:クラスとメソッドはメモリでどう扱われる?

Last updated at Posted at 2024-12-10

オブジェクト指向を深掘り:クラスとメソッドはメモリでどう扱われる?

はじめに

オブジェクト指向プログラミング(OOP)は、プログラムを「オブジェクト」という単位で設計・実装する手法です。この「オブジェクト」や「クラス」「メソッド」は、メモリ上でどのように登録・利用されているのでしょうか?この記事では、これらの仕組みを解説し、OOPの背後で動作するプロセスを紐解きます。


目次

  1. オブジェクト指向の基本概念
  2. クラスとインスタンスの違い
  3. クラスやメソッドのメモリ管理(プロトタイプチェーン含む)
  4. 実践例:メモリ上での動きの流れ
  5. おわりに

1. オブジェクト指向の基本概念

オブジェクト指向プログラミングは以下の3つの要素を中心に構成されています。

  1. カプセル化
    • データ(プロパティ)とそれに関連する処理(メソッド)をひとつの単位(オブジェクト)として扱います。
  2. 継承
    • 既存のクラスの特徴を引き継ぎ、新しいクラスを定義できます。
  3. ポリモーフィズム(多態性)
    • 同じインターフェースを用いて異なる動作を実現します。

これらの特徴を活かしてプログラムを設計することで、再利用性や保守性が高まります。


2. クラスとインスタンスの違い

  • クラスは「設計図」の役割を果たします。属性(プロパティ)や振る舞い(メソッド)を定義します。
  • インスタンスはクラスから作成される実際のオブジェクトで、メモリ上に存在します。

例として、以下のクラスとインスタンスを考えます:

class Car {
  constructor(public brand: string, public speed: number) {}

  drive(): void {
    console.log(`${this.brand} is driving at ${this.speed} km/h`);
  }
}

const car1 = new Car('Toyota', 120); // インスタンス生成
car1.drive(); // "Toyota is driving at 120 km/h"
  • Carはクラス。メモリ上では共有情報として扱われます。
  • car1はインスタンス。メモリ上に個別のデータとして配置されます。

3. クラスやメソッドのメモリ管理

3.1 クラスの登録

クラスが定義されると、その型情報がメモリに登録されます。この型情報には以下が含まれます:

  • メソッド(例:drive
  • 静的プロパティ・静的メソッド(もしあれば)

クラスのメソッドは通常、メモリ上に一度だけ格納され、すべてのインスタンスから共有されます。


3.2 インスタンスの生成

クラスからインスタンスを生成すると、新しいメモリ領域が確保され、以下の内容が格納されます:

  1. プロパティ: brandspeedなどのデータ。インスタンスごとに異なる値を持つ。
  2. 隠された参照(プロトタイプ): クラスの共有情報(メソッドなど)を参照。

3.3 プロトタイプチェーンの仕組み

JavaScriptのクラスは、内部的にプロトタイプチェーンという仕組みを使っています。

  • インスタンスのプロパティやメソッドを呼び出すとき、まずそのインスタンス自身を調べます。
  • 存在しない場合、インスタンスの __proto__ [[Prototype]](プロトタイプ)を参照します。
  • クラス内で定義されたメソッドは、このプロトタイプに登録されています。

例:

const car1 = new Car('Toyota', 120);
car1.drive(); // 実際にはReflect.getPrototypeOf(car1).driveを参照

car1Reflect.getPrototypeOf(car1).driveを通じてCar.prototypedriveメソッドにアクセスしています。


4. 実践例:メモリ上での動きの流れ

以下のコードを例にメモリの流れを考えます:

class Animal {
  constructor(public name: string) {}

  speak(): void {
    console.log(`${this.name} makes a sound`);
  }
}

const dog = new Animal('Dog');
dog.speak();

メモリでの動き

  1. クラスの型情報が登録

    • Animalクラスがメモリに登録され、Animal.prototypespeakメソッドが格納されます。
  2. インスタンス生成

    • dogというインスタンスがメモリ上に作成され、nameプロパティが'Dog'として保存されます。
    • Reflect.getPrototypeOf(dog)Animal.prototypeを参照します。
  3. メソッド呼び出し

    • dog.speak()を呼び出すと、dog自身にspeakが存在しないため、Reflect.getPrototypeOf(dog)(つまりAnimal.prototype)を調べます。
    • Animal.prototype.speakが見つかり、実行されます。

5. よくある疑問と回答

Q1: メソッドはインスタンスごとに複製されますか?

A1: 通常は複製されません。メソッドはクラスのプロトタイプに登録され、すべてのインスタンスで共有されます。ただし、インスタンス独自の関数を定義した場合は個別に保存されます。

例:

dog.speak = function () {
  console.log('Dog barks');
};

この場合、dogのメモリ内に独自のspeakメソッドが追加されます。

Q2: クラスやインスタンスのメモリはいつ解放されますか?

A2: メモリは参照がなくなったタイミングでガベージコレクタ(GC)によって自動的に解放されます。

Q3: TypeScriptはオブジェクト指向プログラミング?

A3: TypeScriptはオブジェクト指向プログラミング(OOP)の概念を取り入れていますが、本質的にはJavaScriptを基盤としており、JavaScript自体が純粋なオブジェクト指向言語ではありません。そのため、TypeScriptも厳密には「オブジェクト指向言語」とは言えません。

理由

  1. JavaScriptのプロトタイプベースの性質
    TypeScriptはJavaScriptのスーパーセットであるため、クラスやインターフェースなどのOOP的な構文を提供しますが、内部的にはJavaScriptのプロトタイプベースの仕組みを利用しています。

    • TypeScriptのclassextendsは、最終的にはJavaScriptのprototypeを使って実装されます。
  2. 純粋なオブジェクト指向言語との違い

    • JavaやC#などの純粋なオブジェクト指向言語は、すべての要素がオブジェクトとして扱われます。
    • 一方、JavaScriptではプリミティブ型(例:numberstring)はオブジェクトではありません。ただし、これらは必要に応じてラッパーオブジェクトとして扱われます。
  3. 型情報が実行時には存在しない
    TypeScriptは型システムを提供しますが、これらの型情報はコンパイル時のみ使用され、実行時には完全に取り除かれます。そのため、実行時に型安全性を保証する仕組みはありません。

TypeScriptとオブジェクト指向の関係

  • TypeScriptは、構文レベルではオブジェクト指向の設計をサポートしています(クラス、インターフェース、抽象クラス、継承、ポリモーフィズムなど)。
  • 実行時には、JavaScriptのプロトタイプベースの性質を利用してこれをシミュレートしています。
  • そのため、「TypeScriptはオブジェクト指向プログラミングをサポートするが、純粋なオブジェクト指向言語ではない」と言えます。

まとめ

  • TypeScriptはJavaScriptの制約を克服し、OOPの構文と設計をプログラマーに提供するための言語です。
  • ただし、TypeScriptが生成するJavaScriptコードの動作を見ると、プロトタイプベースの特性が現れており、純粋なOOP言語ではないことがわかります。
  • TypeScriptを使用する際には、「OOPの構文を使ってプロトタイプベースの仕組みを利用している」という理解が重要です。

おわりに

クラスやメソッドがメモリでどのように管理されているのかを理解すると、コードの効率化やデバッグがより直感的に行えるようになります。特に、JavaScriptのプロトタイプチェーンや共有メモリの仕組みを意識することで、無駄のない設計が可能になります。次回は、ガベージコレクタの動きやオブジェクトのライフサイクルについて深掘りしていきます!

5
0
2

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
5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?