プログラミング/JavaScript で学ぶプロトタイプベースオブジェクト指向プログラミング

出典: フリー教科書『ウィキブックス(Wikibooks)』

JavaScriptはプロトタイプベースのオブジェクト指向言語であり、クラスベースのオブジェクト指向言語とは異なるアプローチを採用しています。以下では、JavaScriptでプロトタイプベースのオブジェクト指向プログラミングを学ぶための基本的な概念を紹介します。

プロトタイプ[編集]

プロトタイプは、オブジェクトの原型を表します。JavaScriptでは、すべてのオブジェクトはプロトタイプを持ち、そのプロトタイプは別のオブジェクトとして定義されます。オブジェクトが持つプロパティやメソッドは、そのオブジェクトのプロトタイプから継承されます。

以下は、プロトタイプを定義する方法の一例です。

function Person(name) {
  this.name = name;
}

Person.prototype.greet = function() {
  console.log(`Hello, my name is ${this.name}.`);
}

const john = new Person('John');
john.greet(); // Hello, my name is John.

この例では、Personというコンストラクタ関数を定義し、そのプロトタイプにgreetというメソッドを追加しています。newキーワードを使ってPersonをインスタンス化し、greetメソッドを呼び出すことができます。

プロトタイプチェーン[編集]

JavaScriptでは、オブジェクトが持つプロパティやメソッドが存在しない場合、そのオブジェクトのプロトタイプから順に探索が行われます。この探索の仕組みをプロトタイプチェーンと呼びます。

以下は、プロトタイプチェーンを利用する例です。

function Person(name) {
  this.name = name;
}

Person.prototype.greet = function() {
  console.log(`Hello, my name is ${this.name}.`);
}

function Employee(name, title) {
  Person.call(this, name);
  this.title = title;
}

Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee;
Employee.prototype.work = function() {
  console.log(`${this.name} is working as a ${this.title}.`);
}

const bob = new Employee('Bob', 'Manager');
bob.greet(); // Hello, my name is Bob.
bob.work(); // Bob is working as a Manager.

この例では、Employeeというコンストラクタ関数を定義し、Personから継承してgreetメソッドを利用しています。Object.createメソッドを使ってPerson.prototypeを継承したEmployee.prototypeを定義し、Employee自身のworkメソッドを追加しています。newキワードを使ってEmployeeをインスタンス化し、greetメソッドとworkメソッドを呼び出すことができます。

クラスのような構文[編集]

ES6以降、JavaScriptではクラスのような構文が導入され、より簡潔にプロトタイプベースのオブジェクト指向プログラミングを行うことができるようになりました。

以下は、クラスのような構文を使った例です。

class Person {
  constructor(name) {
    this.name = name;
  }
  
  greet() {
    console.log(`Hello, my name is ${this.name}.`);
  }
}

class Employee extends Person {
  constructor(name, title) {
    super(name);
    this.title = title;
  }
  
  work() {
    console.log(`${this.name} is working as a ${this.title}.`);
  }
}

const alice = new Employee('Alice', 'Engineer');
alice.greet(); // Hello, my name is Alice.
alice.work(); // Alice is working as a Engineer.

この例では、classキーワードを使ってPersonクラスとEmployeeクラスを定義し、extendsキーワードを使ってPersonを継承しています。また、constructorメソッドを定義してインスタンスの初期化を行い、それぞれのクラスにメソッドを追加しています。superキーワードを使って親クラスのコンストラクタやメソッドを呼び出すこともできます。

プロトタイプベースのオブジェクト指向プログラミング言語の長所と短所[編集]

プロトタイプベースのオブジェクト指向プログラミング言語には、以下のような長所と短所があります。

長所
  1. ダイナミックなオブジェクトの生成が可能  — プロトタイプベースな言語では、オブジェクトのプロパティやメソッドを動的に変更することができます。これにより、実行時にオブジェクトの構造を変更することができます。また、オブジェクトの生成方法も柔軟で、必要なときにオブジェクトを生成することができます。
  2. 継承が柔軟で効率的  — プロトタイプベースな言語では、継承が柔軟で効率的に行えます。オブジェクトのプロトタイプを変更することで、継承を実現することができます。また、プロトタイプチェーンを使って継承を実現するため、多重継承が可能です。
  3. 言語のシンプルさ  — プロトタイプベースな言語は、オブジェクト指向プログラミングに必要な機能だけを持ち、シンプルであることが多いです。そのため、学習コストが低く、コードを書くのに必要な時間が短くて済むことがあります。
短所
  1. プログラマーの間での共通理解が困難  — プロトタイプベースな言語は、従来のクラスベースな言語とは異なる概念を持つため、プログラマーの間での共通理解が困難であることがあります。また、プログラマーがプロトタイプベースな言語を学ぶ際に、新しい概念や考え方を習得する必要があるため、学習コストが高いことがあります。
  2. プロトタイプの動的な変更が予期しない副作用をもたらすことがある  — プロトタイプベースな言語では、オブジェクトのプロトタイプを動的に変更することができますが、このような変更が予期しない副作用をもたらすことがあるため、注意が必要です。
  3. パフォーマンスの低下  — プロトタイプベースな言語は、プロトタイプチェーンをたどる必要があるため、クラスベースな言語よりもパフォーマンスが低下することがあります。特に、複雑なオブジェクトの構造を持つ場合や、プロトタイプチェーンの深さが深い場合には、パフォーマンスの問題が顕著になることがあります。
  4. エラーが発生しやすい  — プロトタイプベースな言語は、動的に変更されるオブジェクトのプロパティやメソッドが、予期しない場所で参照されたり、変更されたりすることがあります。このような場合、エラーが発生する可能性が高くなるため、注意が必要です。
  5. オブジェクトの識別が困難  — プロトタイプベースな言語では、オブジェクトがどのようなプロトタイプチェーンを持つかによって、その性質が決まるため、オブジェクトの識別が困難になることがあります。特に、多重継承を使用する場合には、どのプロトタイプチェーンがどのオブジェクトに属するかが複雑になるため、識別が困難になることがあります。

以上が、プロトタイプベースのオブジェクト指向プログラミング言語の長所と短所です。プログラマーは、自分が開発するアプリケーションの要件に合わせて、プロトタイプベースな言語を選択するか、クラスベースな言語を選択するかを判断する必要があります。

プロトタイプベースのオブジェクト指向プログラミング言語用語集[編集]

以下は、プロトタイプベースのオブジェクト指向プログラミング言語に関連する用語集です。

  • オブジェクト:プロトタイプベースな言語において、すべての値はオブジェクトとして扱われます。オブジェクトは、プロパティと呼ばれる名前と値のペアの集合を持ち、メソッドと呼ばれる関数を実行することができます。
  • プロトタイプ:プロトタイプは、オブジェクトのテンプレートのようなものであり、新しいオブジェクトを作成する際に参照されます。プロトタイプは、プロパティとメソッドを持ち、新しいオブジェクトにこれらを継承することができます。
  • プロトタイプチェーン:プロトタイプチェーンは、オブジェクトの継承関係を示すものであり、オブジェクトが持つプロパティやメソッドがどのようなプロトタイプから継承されたかを示します。プロトタイプチェーンは、オブジェクトの __proto__ プロパティをたどることで辿ることができます。
  • コンストラクタ:コンストラクタは、新しいオブジェクトを作成するための関数であり、通常は大文字で始まる名前を持ちます。コンストラクタを呼び出すことで、新しいオブジェクトが作成され、そのオブジェクトのプロトタイプが指定されたものになります。
  • インスタンス:インスタンスは、コンストラクタを呼び出して作成されたオブジェクトのことを指します。インスタンスは、そのコンストラクタが持つプロパティとメソッドを継承します。
  • 多重継承多重継承とは、あるオブジェクトが複数のプロトタイプを継承することを指します。プロトタイプチェーンにおいて、多重継承を使用する場合には、どのプロトタイプチェーンがどのオブジェクトに属するかが複雑になることがあります。
  • mixin:mixinは、既存のオブジェクトに新しいプロパティやメソッドを追加するための方法であり、複数のオブジェクトから機能を取り込むことができます。mixinは、プロトタイプベースな言語において特によく使われる技法の一つであり、コードの再利用性を高めることができます。
  • クラス:プロトタイプベースな言語において、クラスは存在しませんが、一部の言語ではクラス風の構文を提供しています。クラス風の構文を使用することで、プロトタイプベースな言語でも、クラスベースの言語のようなコーディングスタイルでプログラムを書くことができます。
  • オブジェクトリテラル:オブジェクトリテラルは、オブジェクトを直接記述するための構文です。オブジェクトリテラルを使用することで、新しいオブジェクトを簡単に作成することができます。
  • ファクトリ関数:ファクトリ関数は、新しいオブジェクトを作成するための関数であり、通常は小文字で始まる名前を持ちます。ファクトリ関数は、オブジェクトを生成するための手順をカプセル化し、コードの再利用性を高めることができます。
  • this:thisは、現在のオブジェクトを参照するためのキーワードであり、メソッド内で使用されます。thisを使用することで、メソッドが呼び出されたオブジェクト自身を参照することができます。
  • call, apply, bind:call、apply、bindは、thisを設定するためのメソッドであり、関数内でthisを使ってオブジェクトを参照する場合に使用されます。call、apply、bindを使用することで、関数が実行される際にthisがどのオブジェクトを参照するかを明示的に指定することができます。

以上が、プロトタイプベースのオブジェクト指向プログラミング言語に関連する用語集です。

プロトタイプベースのオブジェクト指向プログラミング言語便覧[編集]

プロトタイプベースのオブジェクト指向プログラミング言語は、多数存在します。以下に、その中から代表的なものをいくつか紹介します。

JavaScript

JavaScriptは、Webブラウザで動作するスクリプト言語であり、現在最も広く使用されているプロトタイプベースな言語の一つです。JavaScriptは、オブジェクトをプロトタイプチェーンで継承することができ、また、mixinを使用することで複数のオブジェクトから機能を取り込むことができます。

Lua

Luaは、軽量で高速なスクリプト言語であり、プロトタイプベースな言語の一つです。Luaは、オブジェクトをテーブルとして表現し、テーブルの中に他のテーブルを含めることで継承を実現します。

Self

Selfは、オブジェクト指向プログラミング言語の一つであり、プロトタイプベースな言語の先駆けとなりました。Selfは、オブジェクトをプロトタイプとして表現し、プロトタイプから継承することで、オブジェクトの振る舞いを定義します。

Io

Ioは、小規模なスクリプト言語であり、プロトタイプベースな言語の一つです。Ioは、メッセージパッシングによってオブジェクト間の通信を行います。また、Ioは、プロトタイプをコピーして新しいオブジェクトを作成することで継承を実現します。

NewtonScript

NewtonScriptは、AppleのPDA「Newton」で使用されたスクリプト言語であり、プロトタイプベースな言語の一つです。NewtonScriptは、オブジェクトをスロットとして表現し、スロットから継承することで、オブジェクトの振る舞いを定義します。

以上が、プロトタイプベースのオブジェクト指向プログラミング言語の一部です。他にも多数の言語が存在します。

まとめ[編集]

JavaScriptでは、プロトタイプベースのオブジェクト指向プログラミングが採用されています。プロトタイプはオブジェクトの原型を表し、プロトタイプチェーンによって継承が行われます。ES6以降では、クラスのような構文が導入され、より簡潔にプロトタイプベースのオブジェクト指向プログラミングを行うことができます。