• 編集プロダクション・リブロワークスのWebサイト

    今回の社員ブログのテーマは「プロトタイプベース言語について改めて整理する」です。

    最近、オブジェクト指向について説明した原稿を編集する機会がありました。オブジェクト指向はプログラミングにおいてお馴染みの考え方ですが、オブジェクト指向の解説では、基本的にクラスベースについて触れることが多く、プロトタイプベースに触れることはあまりありません。しかし、プロトタイプベースについても知っておくと、オブジェクト指向についての理解がより深まります。そのため、一度整理しておきたいと思いました。

    プロトタイプベース言語とは

    プロトタイプベース言語とは、オブジェクト指向プログラミング言語の1種で、変数(データ)やメソッドをクラスに依存せずに追加できるようにしたもののことです。プロトタイプベース言語の代表的なものには、JavaScriptがあります。

    対して、クラスベース言語もオブジェクト指向プログラミング言語の1種で、変数とメソッドをクラスという単位で定義できるようにしたもののことです。クラスベース言語の代表的なものには、C++やJavaがあります。

    JavaScriptはプロトタイプベース言語と述べましたが、ECMAScript2015でclass構文が導入された関係で、JavaScriptでもクラスを定義できるようになりました。

    JavaScriptでクラスを定義すると、以下のようなコードになります。

    クラスが定義できるようになっため、プロトタイプベースという概念を理解する必要は無いという考え方もあります。

    しかしJavaScriptのclass構文は、内部的にはプロトタイプベースのしくみに変換されています。つまりclass構文は、可読性や書きやすさのための構文(糖衣構文)です。そのため、プロトタイプベースについて理解しておくに越したことはありません。

    プロトタイプベース言語のしくみ

    プロトタイプベース言語であるJavaScriptではどのようなしくみになっているのか、2つの点について見ていきましょう。class構文を使う書き方もできますが、以降の内容は、あくまでclass構文を使わないことを前提とします。

    ①オブジェクトの生成

    オブジェクトを生成する際、その元になるオブジェクト(プロトタイプ)を指定します。たとえば標準組み込みオブジェクトであるObjectをもとに新たなオブジェクトを生成したい場合は、次のようにします。

    次のようにかんたんに書くこともできます。

    クラスがないのにnew演算子を使えるのは、クラスベース言語に慣れている人にとって、わかりづらい点です。JavaScriptのnew演算子は、その元になるオブジェクトから新しいオブジェクトを生成するもの、と理解しておくとよいでしょう。

    また、関数をもとに新たなオブジェクトを生成することも可能です。

    ②継承

    JavaScriptにはクラスがなかったと説明しましたが、オブジェクト指向における「継承」はどのように実現していたのでしょうか。

    JavaScriptにはプロトタイプチェーンというしくみがあり、この機能を使うと継承を実現できます。

    JavaScriptのオブジェクトには「__proto__」プロパティが自動で用意されます。自分自身に存在しないプロパティやメソッドが呼び出されると「__proto__」プロパティを辿り、その先に対象のプロパティやメソッドがないかを探しにいきます。これがプロトタイプチェーンです。クラスを定義せずに、オブジェクトがほかのオブジェクトの機能を継承できることを表します。

    JavaScriptのコードを見てみましょう。

    user1.__proto__は、user.prototypeという自動で用意されるプロパティへの参照を持つしくみになっています。

    そのため、その関数をもとに生成したオブジェクトでも継承したい機能は、prototypeに記述しておきます。そうすると、user1.__proto__にhelloへの参照が含まれるので、user1でもhelloを呼び出すことが可能になります。

    まとめ

    JavaScriptの初心者向けの書籍だとプロトタイプベースや継承については載っていないこともあるので、馴染みがない方もいるかもしれません。しかしプログラミングでは、文法そのものだけではなく、アーキテクチャの理解も深めておくと「だからこの文法になっているのか」と腑に落ちる場合があります。また、ほかの言語のアーキテクチャを知ると比較ができるので、いま自分が使っているプログラミング言語の理解を深めることにも繋がります。

    自分が知っているプログラミング言語だけについ気をとられてしまいますが、たまには違うプログラミング言語やアーキテクチャを学び、俯瞰して見れるように気をつけていきたいと思います。

    参考

    https://developer.mozilla.org/ja/docs/Learn/JavaScript/Objects/Inheritance

    https://developer.mozilla.org/ja/docs/Learn/JavaScript/Objects/Object_prototypes

    https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Details_of_the_Object_Model

    https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/new