Intelligent Technology's Technical Blog

株式会社インテリジェントテクノロジーの技術情報ブログです。

JavaScriptでClass

こんにちは。出石です。
JavaScript(以下JS)のEcmaScript6(以下ES6)の草案によるとClass構文がサポートされて行くようなのでどのような感じかを調べてみました。
尚、各ブラウザでは未実装なので、動作検証にはtraceurを利用しました。

JavaScriptのクラス

JS自体にはクラスの概念はありませんが、プロパティとメソッドをもつオブジェクトはこれまでも以下のように書いてきたと思います。

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

ClassA.prototype.speak = function() {
	console.log('speak() : 名前は' + this.name + 'です');
};

var yamada = new ClassA('Yamada');
yamada.speak();

しかし、コンストラクタメソッドの定義が分かれていたりJavaC++のようなまとまり感がなくわかりずらい点もあります。

この実装をES6のClass構文で書くと以下のようになるようです。

class ClassA {

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

	speak() {
		console.log('speak() : 名前は' + this.name + 'です');
	}
}

var yamada = new ClassA('Yamada');
yamada.speak();

まずはClass構文として「class」があり、続いてクラス名、定義ブロックと続きます。
メソッド定義は短縮定義のように記述しメソッドの区切りにカンマは付きません。
constructor()がクラスコンストラクタで、speak()がクラスメソッドになります。

ES6はこちらを参照。
ES6 Working Draft

しかしこのClass構文はこれまでの「関数定義とprototypeプロパティのメソッド定義」の糖衣構文(syntactic sugar)でクラスの概念が追加される訳ではありません。

なので、これまでどおりの記述方法でも動作に違いはないと思います。
が、JavaC++に慣れてる人にはこれまでより分かりやすい(保守しやすい)コードになるのではないでしょうか。

クラスの継承

次は継承関係を見てみたいと思います。
まずはES6でのClass構文だと以下のようになります。

class ClassA {

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

	speak() {
		console.log('speak() : 名前は' + this.name + 'です');
	}
}

class ClassB extends ClassA {
	constructor(name) {
		super(name);
	}

	talk() {
		super.speak();
	}
}

var yamada = new ClassB('Yamada');
yamada.talk();

「extends」や「super」もJavaC++を経験されている方には馴染みやすいと思います。


これを現在の構文で実現しようとすると少々分かりにくい記述になってきます。

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

ClassA.prototype.speak = function() {
	console.log('speak() : 名前は' + this.name + 'です');
};

function ClassB(name) {
	ClassA.call(this, name);
}

ClassB.prototype = Object.create(ClassA.prototype);
ClassB.prototype.constructor = ClassA;

ClassB.prototype.talk = function() {
	ClassA.prototype.speak.call(this);
};

var yamada = new ClassB('Yamada');
yamada.talk();

ポイントはcall()で親クラスメソッドをthisで実行したり、親のprototypeを自分に設定する箇所でしょうか。

ここまでのソースをClass構文を使用した「class.js」とClass構文を使用しない「notclass.js」として保存しておきます。

traceur

今度は実際にClass構文で作成したソースを確認する為に、traceurを使ってみたいと思います。
traceurはGoogleで作成されたES6形式で書かれたJSをES5の形式に変換してくれるツールです。
以下で公開されています。
traceur-compiler
また、nodeモジュールでインストールする事もできます。

$ npm install --global traceur

インストールが出来たら、保存しておいたサンプルソースをtraceurで確認してみます。

tracerの使い方は、コマンドでClass構文のJSを入力ファイルにして実行するか、Class構文のJSをコンパイルし、traceur-runtime.jsと結合して実行する方法があります。

入力ファイルで実行

$ traceur class.js

コンパイルしてランタイムと結合し実行

$ traceur --out build.js --script class.js
$ cat C:\Users\XXXX\AppData\Roaming\npm\node_modules\traceur\bin\traceur-runtime.js build.js > exec.js
$ node exec.js

※C:\Users\XXXX\・・・\npmはtraceurをインストールした場所です
コンパイル結果「build.js」は中を見てみるとClass構文を使わないソースに重なる箇所が見てとれると思います。

nodeで実行するならコンパイルしたbuild.jsでtracerをrequireしても可能です。


それぞれの実行結果は、以下が出力されます。

$ speak() : 名前はYamadaです

前述のようにES6のClass構文は糖衣構文なので、Class構文を使わない書式でも同様の結果が確認できます。

$ node notclass.js

他の草案

ES6では、他にも「デフォルトパラメータ」「アロー関数」「for・・・of」など使えたら便利な機能がまだまだあります。
参考までに各ブラウザのサポート状況を見てみるのもいいかもしれません。
FireFox等で既にサポートしている機能もあるようです。(今回は未確認)

ES6の実装がいつになるかは分かりませんが、改めてJSは柔軟な言語だなと認識しました。