面倒くさいJavascriptの整理−クラス編

 Javascriptでクラスの書き方は色々あるのでまとめ

1.クラスの宣言

クラスの宣言は特別な書き方はなく関数の宣言と同じ。

function SuperClass(){
}

この関数がSuperClassクラスのコンストラクタになる。

2.メンバ変数の宣言

メンバ変数はthisをつけて宣言する。
thisの意味さえ分かっていれば問題ない。

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

当たり前だけど、メンバ変数はコンストラクタでしか宣言できない(多分)。
アクセス修飾子はないから、全部public。遮蔽もやろうと思えばやれないことはないだろうけど、特に意味がなさそう。

3.メンバ関数

メンバ関数の書き方がいろいろあってよく分からない。
調べてみたら、大体これくらいあった。
1.コンストラクタ内で内部関数として宣言する。

function SuperClass(name){
   this.name = name;
   this.getName = function(){
       return this.name;
   }
}

この方法は処理が長くなるとコンストラクタが見難くなる。

2.コンストラクタ外で外部関数として宣言しメンバ関数として関連付ける。

function SuperClass(name){
   this.name = name;
   this.getName = getName;
}

function getName(){
   return this.name;
}

やり方としてはいい感じだけど、関数名のスコープが非常に気になる。

3.クラス名.prototype.関数名() {処理}。

function SuperClass(name){
   this.name = name;
   function SuperClass.prototype.getName(){
       return this.name;
   }
}

クラス名.prototypeが何なのか不明。
Javascriptで静的アクセス可能なフィールドがあることを初めて知った。
使い方がおかしいのかもしれないが、operaFirefoxでは動作せず。。。

4.コンストラクタ外で外部関数として宣言しクラスの静的prototypeに関連付ける。

function SuperClass(name){
   this.name = name;
}
SuperClass.prototype.getName = function(){
       return this.name;
}
静的フィールドを使うので無駄な処理は省かれる。
また、静的フィールドに割り当てられるので無名関数を使え、関数名の衝突を気にする必要がなくなる。
しかしグローバル領域で宣言及び代入することになるので、宣言が散ってしまう。

 標準的には4の方式がよいとされているらしいが個人的にはJavascriptでクラスのメンバー関数を書くときは1の方式で書くのが良いのではないかと思われる。しかし1、2方式はインスタンスを作成するとその都度コンストラクタでプロトタイプが設定されるため、大量にインスタンスを作成するときは注意が必要。

 2の方式もC++チックで結構いい感じだが、Javasciptではネームスペースを宣言できるか不明なのでプロパティ名と実際の関数名を変えるなど自力で何か対策をしないと継承させるときに泣く羽目になる。

 3はIEでしか動かないので論外。

 4は標準的な方法でお仕事で使う場合。

でもこれ、極端な話アドレスバーからもクラスを拡張できてしまうのでこの機能はどうなんでしょうか。

 またvarの使い方には注意が必要。

他のプログラミング言語に慣れていると、クラスの処理を書くときにはメンバー変数として残しておきたい値はthisで、一時的な計算変数はvarで宣言するという感覚で使用するだろう。

しかし、1方式の場合、thisではなくvarでアクセスしても見かけ上は問題なく参照できてしまう。

1方式のメンバー関数の記述の場合、コンストラクタ(newの対象となる関数)内ではできるだけ、var宣言をしないということが重要だ。

一応、問題となるソースを挙げておく。

ex1)
function SuperClass()
{
	var value = 1;
	this.getValue = function ()
	{
		return value;
	}
	this.addValue = function ()
	{
		value++;
	}

}
ex2)
var value = 1;
function SuperClass()
{
	this.getValue = function ()
	{
		return value;
	}
	this.addValue = function ()
	{
		value++;
	}
}

参照している変数スコープが違うので、非常にマズイことが分かる。

まあ、2、4方式の場合でも変数スコープが問題ではあるが、ex1)のような場合値を返さない分、気づきやすいと言える。