Javascriptのオブジェクト指向は分かりにくい

  • 投稿日:
  • by
  • カテゴリ:

HTML5の時代になると、アプリケーションロジックはJavascriptで書かれることになる。現在はC++やJavaで書かれているアプリケーションがJavascriptで書かれる。データベースは長年支配的だったSQLからJavaScriptと親和的なIndexedDBに代わる。

しかし、本当にそんな時代が来るのだろうか?

C++とJavaは文法が比較的近いので、どちらか一方が分かればもう一方を習得するのは難しくない。しかしJavascriptはC++やJavaとは基本的な枠組みが違う。C++やJavaはクラスベースのオブジェクト指向で、クラスをインスタンス化してオブジェクトを作るのに対し、JavaScriptはプロトタイプベースのオブジェクト指向で、既存のオブジェクトをプロトタイプとして新しいオブジェクトを作る。C++やJavaに慣れ親しんできた私にとって、これはなかなか理解しにくい。

Javascriptにはオブジェクトを作成する方法が大きく分けて二つある。オブジェクトリテラルを使う方法と、関数オブジェクトに対してnew演算子を使う方法だ。

オブジェクトリテラルを使う方法は以下のようになる。

var testObj = {
	strValue: "Hello",
	testFunc: function() {
		this.strValue = "Bye";
	},
	showValue: function() {
		alert(this.strValue);
	}
};
testObj.testFunc();
testObj.showValue();

私がKmoneyの元ネタにしているSQL Managerではこの方法が使われている。しかし、オブジェクトリテラルは元々はデータ構造を表現するためにあるはずなので、そこに関数の定義を含めるのは違和感がある。各メンバーがセミコロンではなくカンマで区切られるのも単純ミスの原因になる。

関数オブジェクトに対してnew演算子を使う方法は、クラスベースのオブジェクト指向に慣れた人間にとって一見親しみやすい。

function TestObject() {
	this.strValue = "Hello";
};
TestObject.prototype.testFunc = function() {
	this.strValue = "Bye";
};
TestObject.prototype.showValue = function() {
	alert(this.strValue);
};
var testObj = new TestObject();
testObj.testFunc();
testObj.showValue();

関数の定義が実質的にコンストラクタとなり、そのあとにprototypeをつけたメンバ関数の定義が続く。メンバ変数の定義はコンストラクタの中に書かれる。しかし、オブジェクトをプロトタイプとしてオブジェクトを作るはずのJavascriptで、クラスをインスタンス化するかのように書いてしまうことには疑問が残る。Javascriptの特性を無視しているように感じる。

継承に関しても、Object.create()を使って実現する方法とprototypeで継承元を設定する方法がある。前者はオブジェクトリテラルを使う方法の延長線上にあり、後者はnew演算子を使う方法の延長線上にある、と考えてよさそうだ。

var secondObj = Object.create(testObj);
secondObj.testFunc = function() {
	this.strValue = "How are you?";
};
secondObj.testFunc();
secondObj.showValue();

function ThirdObject() {
};
ThirdObject.prototype = new TestObject();
ThirdObject.prototype.testFunc = function() {
    this.strValue = "May I help you?";
};

var thirdObj = new ThirdObject();
thirdObj.testFunc();
thirdObj.showValue();

Javascriptの場合、継承といってもC++やJavaとは意味が異なる。C++やJavaで派生クラスをインスタンス化した場合にはオブジェクトは一つしかないのに対し、Javascritでは二つのオブジェクトをprototypeという鎖でつないでいるだけだ。is-a関係は存在せず、特殊なhas-a関係によって継承らしきものを実現している、と考えればよいか。

分かりにくいなあ、というのが正直な印象だ。私の頭がついていけないだけで、HTML5の時代にはみんながこれをスッキリ理解するようになるのだろうか。せめて上記の点については標準的なベストプラクティスが確立して、みんな同じ書き方を採用するようになってほしいものだ。