こんにちは。きんくまです。
今回はオブジェクト指向の書き方についてです。
■ex1
単純なオブジェクト指向
クラス
//-----------------------------
// ClassA
//-----------------------------
var ClassA = function(){
//プロパティ
this.prop1 = 'Hello';
this.prop2 = 'World';
//メソッド
this.method1 = function(){
var message = this.prop1 + ' ' +this.prop2;
alert(message);
};
this.method2 = function(){
alert('method2');
}
}
//クラスプロパティ、クラスメソッド
ClassA.prop3 = 'class prop';
ClassA.method2 = function(){
alert('ClassA method2');
}
それを使う場合
function sample1(){
//インスタンス作成
var myClassA = new ClassA();
alert(myClassA.prop1); //プロパティ
myClassA.method1(); //メソッド
//クラスメンバを使う
alert(ClassA.prop3);
ClassA.method2();
}
こんな感じです。
変数を宣言して、無名関数を代入します。
その無名関数の中のプロパティが、インスタンスメンバーとなります。
クラスメンバーは、「クラス名.メンバ―変数名 = 内容」のようにします。
■ex2 prototypeを使う
さきほどの無名関数内に全てのインスタンスメンバーを入れてもいいのですが、もうひとつやり方があります。
クラス
//-----------------------------
// ClassB
//-----------------------------
var ClassB = function(){
this.prop1 = 'Hello';
this.prop2 = 'World';
}
ClassB.prototype = {
method1: function(){
var message = this.prop1 + ' ' +this.prop2;
alert(message);
},
method2: function(){
alert('method2');
}
}
使う場合
function sample2(){
//インスタンス作成
var myClassB = new ClassB();
alert(myClassB.prop1); //プロパティ
myClassB.method1(); //メソッド
}
使い方は全くかわりません。
クラスの宣言方法が変わっていて、
ClassB.prototype = { インスタンスメンバー }
のようにしています。
ex1のように無名関数内にインスタンスメンバーを入れた場合、そのクラスのインスタンスを作成するとその分だけメモリを消費します。しかし、prototypeを利用すると、prototypeの中に入っているものは1回分のみメモリに確保されます。なので、メモリが節約することができます。
メモリが節約できるのだったら、prototypeにすべてかけばいいじゃん!と思うかもしれません。でもそうしません。「プロトタイプチェーン」という仕組みを理解すると、どうしてそうしないのかがわかるのですが、ここではとりあげません。
なので、私がprototypeを利用する場合は、
●無名関数内にインスタンスのプロパティを
●prototype内にインスタンスのメソッドを
書いています。
このprototypeはその他に、オブジェクト指向の「継承」にも使われるのですが、ここではとりあげません。とばしてばっかりで、すみません。気になる方は「プロトタイプチェーン」「継承」などでググってみてください。
■ex3 名前空間
JavaScriptには、特に名前空間というものはないので自分でオブジェクトを宣言して階層をもたせて擬似的に作ってあげます。
名前空間がかぶっていても特にコンパイルエラーというのもおこらず、そのまま上書きされてしまいます。なので、注意が必要です。
クラス
//-----------------------------
// ClassC
//-----------------------------
var com = {};
com.kuma_de = {};
com.kuma_de.ClassC = function(){
this.prop1 = 'ClassC';
}
com.kuma_de.ClassC.prototype = {
method1: function(){
alert(this.prop1);
}
}
使う場合
function sample3(){
var myClassC = new com.kuma_de.ClassC();
myClassC.method1();
}
■ex4 前回のタブメニューをオブジェクト指向のクラスにおきかえてみました。
JavaScript
//-----------------------------
// ex4
//-----------------------------
var ex4 = {};
ex4.Main = function(){
this.currentMenu = 1;
};
ex4.Main.prototype = {
init: function(){
this.registerEvent();
this.activateMenu(this.currentMenu, true);
},
activateMenu: function(menuNo, isActive){
var menu = $('#ex4_menu' + menuNo);
if(isActive){
menu.attr('class', 'active');
}else{
menu.attr('class', '');
}
},
registerEvent: function(){
//無名関数内から参照できるように保持
var self = this;
for(var i = 0; i < 3; i++){
var _no = i + 1;
$('#ex4_menu' + _no)
.bind('mouseover', {no: _no}, function(e){
if(self.currentMenu != e.data.no){
self.activateMenu(e.data.no, true);
}
})
.bind('mouseout', {no: _no}, function(e){
if(self.currentMenu != e.data.no){
self.activateMenu(e.data.no, false);
}
})
.bind('click', {no: _no}, function(e){
//古いものは元に戻す
self.activateMenu(self.currentMenu, false);
//新しいものに設定
self.currentMenu = e.data.no;
self.activateMenu(self.currentMenu, true);
$('#ex4_content_wrapper')
.stop()
.animate({marginLeft:(self.currentMenu - 1) * -200 + 'px'}, 500, "swing");
});
}
}
};
使うとき
$(function(){
var myMain = new ex4.Main();
myMain.init();
});
前回のものと比べてみてください。ポイントは以下の部分です。
jQueryのイベント割り当てのときは、無名関数内に処理をかきます。そのときthisを使うとインスタンスメンバーを指すthisではなく、イベントを割り当てているDOM要素そのものを指すthisとなります。
なので、インスタンスをどこかで確保しておかないと、インスタンスのメソッドを呼べませんそのため途中で
var self = this;
ということをしています。