はじめに前置き
CakePHPなどでWebアプリケーションを書いてて、JavaScript側のコードが思ったように書けずに苦労するケースが割りとあるのかなと思ってます。
その要因となるものは色々あると思うのですが、考えられるものの1つとして、PHPでのクラス定義とJavaScriptでのクラス定義とがうまく対比できない所にあるのかなと思って、参考になる情報がないかググってみました。
PHPとJavaScriptにおけるオブジェクト指向を比較するというスライドは情報はとてもまとまってるのですが、自分が探していたそれぞれの言語でのクラス定義の方法を対比させるようなコード例が出ておらず、しかたがないので自分でコードを書いて対比させて折角なのでドキュメントにまとめることにしました。
注意
- JavaScriptでのクラス定義の方法は色々なアプローチがあると思うのですが、自分がなれ親しんでるCoffeeScriptで生成されるJavaScriptのクラスをサンプルとして活用してます。
- PHPほとんど書いたこと無いのでPHPでのクラス定義が適切で無い可能性あるのでツッコミお願いします
確認した環境
- Mac OS X 10.9.5
- PHP
- PHP 5.4.30 (cli) (built: Jul 29 2014 23:43:29)
- JavaScript
- Node.jsで確認
- v0.10.13
基本的なクラス定義の方法
メンバー変数にmessageを持ったSimpleClassクラスというものを考えてみました。
PHPの場合
class SimpleClass {
public $message = 'Public';
}
となるかと思います
JavaScriptの場合
var SimpleClass;
SimpleClass = (function(){
function SimpleClass() {
this.message = 'Public';
}
return SimpleClass;
})();
という形になります。
参考まで上記のJavaScriptを生成したCoffeeScript
もしかしたらPHPを書き慣れてる方にはCoffeeScriptの方が意図が伝わりそうな気がするのでCoffeeScriptでのコードも書いておきます
class SimpleClass
constructor:() ->
@messsage = 'Public'
インスタンス化してパブリックな変数をターミナル上に表示する
PHPの場合
newしてインスタンス化した上で、メンバー変数を以下のようにして呼び出すことが出来ます
class SimpleClass {
public $message = 'Public';
}
$obj = new SimpleClass();
print $obj->message;
JavaScriptの場合
クラス定義はちょっと違和感があるかもしれませんが、メンバー変数を呼び出す方法はPHPのそれとあまり大差がないかと思います。
var SimpleClass;
SimpleClass = (function(){
function SimpleClass() {
this.message = 'Public';
}
return SimpleClass;
})();
var obj = new SimpleClass();
console.log(obj.message);
参考まで上記のJavaScriptを生成したCoffeeScript
CoffeeScriptの場合にも大差がないと思います
class SimpleClass
constructor:() ->
@messsage = 'Public'
obj = new SimpleClass()
console.log(obj.message)
パブリックなメソッドを定義する
さて今度はprintHelloというパブリックなメソッドを定義してみましょう。
PHPの場合
PHPの場合には以下のようになるかと思います。
class SimpleClass {
public $message = 'Public';
public function printHello(){
print("newしたオブジェクトからは呼び出せる");
}
}
$obj = new SimpleClass();
$obj->printHello();
JavaScriptの場合
JavaScriptの場合には、クラス名のSimpleClassの後に、ドット(.)とprototypeを付けて、その後にメソッド名を付けます。prototypeの概念説明はやりだすとキリがない(というかそこまで的確に説明する自信がない)のでこのあたりを読むのが良いのかなと思います。
var SimpleClass;
SimpleClass = (function(){
function SimpleClass() {
this.message = 'Public';
}
SimpleClass.prototype.printHello = function () {
console.log("newしたオブジェクトからは呼び出せる");
};
return SimpleClass;
})();
var obj = new SimpleClass();
obj.printHello();
参考まで上記のJavaScriptを生成したCoffeeScript
CoffeeScriptの場合、function **printHello(){}**に相当する記述が **printHello:() ->**という形でメソッドを定義します。
※CoffeeScriptのメソッド定義の記法に最初違和感を感じるかもしれませんね
class SimpleClass
constructor:() ->
@messsage = 'Public'
printHello:() ->
console.log("newしたオブジェクトからは呼び出せる")
obj = new SimpleClass()
console.log(obj.message)
プライベートな変数とその変数を得るためのメソッドを定義
最後にmsgというプライベートな変数を定義しつつ、その変数を得るためのメソッドを定義してみましょう。
PHPの場合
まず、プライベート変数だけ定義してみます
class SimpleClass {
public $message = 'Public';
private $msg = 'Private';
public function printHello(){
print("newしたオブジェクトからは呼び出せる");
}
}
上記定義した後に
$obj = new SimpleClass();
print $obj->msg;
とするとCannot access private property SimpleClass::$msg というメッセージが表示されるかと思います。
名前の通りプライベートな変数なので外部からは直接呼び出せません。
そこで、このプライベートな変数にアクセスできるgetMsgというパブリックなメソッドを定義します。
class SimpleClass {
public $message = 'Public';
private $msg = 'Private';
function printHello(){
print("newしたオブジェクトからは呼び出せる");
}
public function getMsg(){
print($this->msg);
}
}
上記のようにした上で、以下のようにgetMsg()を通じて、SimpleClassクラスの中で定義されてるプライベートな変数にアクセスして画面表示されます
$obj = new SimpleClass();
$obj->getMsg();
JavaScriptの場合
以下のようにすることで、プライベートなmsg変数を定義できます。パブリックな変数を定義した際には、this.xxxとしましたが、プライベートな変数の場合には、JavaScriptの変数スコープが関数単位である特徴を活かして以下のようにしてあげればプライベートなものとして利用できます。
var SimpleClass;
SimpleClass = (function(){
var msg = 'Private';
function SimpleClass() {
this.message = 'Public';
}
SimpleClass.prototype.printHello = function () {
console.log("newしたオブジェクトからは呼び出せる");
};
return SimpleClass;
})();
上記定義したものに対して
var obj = new SimpleClass();
console.log(obj.msg());
とすると、以下のようにエラーになります。
console.log(obj.msg());
^
TypeError: Object #<SimpleClass> has no method 'msg'
プライベートなmsgにアクセスするために、getMsg()メソッドを定義するには以下のようにします。
var SimpleClass;
SimpleClass = (function(){
var msg = 'Private';
function SimpleClass() {
this.message = 'Public';
}
SimpleClass.prototype.printHello = function () {
console.log("newしたオブジェクトからは呼び出せる");
};
SimpleClass.prototype.getMsg = function () {
console.log(msg);
};
return SimpleClass;
})();
上記定義したものに対して以下のようにすると、画面上にPrivateという文字が表示されます
var obj = new SimpleClass();
console.log(obj.msg());
終わりに
JavaScriptでのクラス定義は、最初なれないと違和感があると思いますし、実際自分も正直、このあたりを素でサクッとは書けません(^_^;)
自分の場合には、Rubyを割りとずっと勉強していたこともありクラス定義については、CoffeeScriptのチカラを借りながらコードを書いていたことでこのあたりの定義については理解が進んだので、そういうのを使いながら、PHPでのそれと近いものを自分なりに見つけながらコードを書いていくのがよいのかと思います。
またJavaScript: The Good Partsあたりの本を読むと、JavaScriptのクラス定義についてより理解が進みやすくなると思います。