« ◇WEBページに行番号付きテキストを張りつける | トップページ | ココログ+firefox試験 »

Javascriptでのクラスの作り方

Javascriptでクラスを作成する方法です。すぐ忘れるのでメモしておきます。

<script type="text/javascript">
//========== クラスpos定義
function pos(x,y){
   this.x= x==undefined? 0 : x;     // インスタンス変数
   this.y= y==undefined? 0 : y;     // インスタンス変数
   }
pos.prototype.sub = function(that){ // メンバ関数-1
   return new pos(this.x-that.x , this.y-that.y);
   }
pos.prototype.abs = function(){     // メンバ関数-2
   return Math.sqrt(this.x*this.x + this.y*this.y);
   }
pos.prototype.toString= function(){ // メンバ関数(文字列化)
   return "["+this.x+","+this.y+"]";
   }
pos.zero = new pos(0,0);            // スタティック変数定義
pos.sub  = function(a,b){           // スタティック関数定義
   return a.sub(b);
   }
//========= 以上posクラス定義、以下posクラス使用例
function test(){
   var pos1= new pos(5,8); // posクラスオブジェクト生成
   var pos2= new pos(2,4); // posクラスオブジェクト生成
   alert("|"+pos1.toString()+"-"+pos2.toString()+"|="
         +(pos1.sub(pos2).abs()) ); // 差分の絶対値を得る
   alert("pos.zero="+pos.zero);                    // スタティック変数参照
   alert("pos.sub(pos1,pos2)="+pos.sub(pos1,pos2));// スタティック関数呼び出し
   }
</script>
<input type=button value=test onClick="test()">

この例は位置を現すクラスposを定義しています。posは2つのメンバ変数を持ちます。 pos同士の差分を求めるsub()関数、と絶対値(原点からの距離)を求めるabs()関数、 および文字列表現をえるtoString()関数を持っています。
[test]ボタンを押すと、posを2つ作りその差分の絶対値をalertで表示します。

Javascriptに於けるクラス定義法は若干分かりづらいものとなっています。
基本的には
 ・クラス名、メンバ変数、構築子を定めるfunction()記述が一つ。関数内でthis使用
  (インスタンス毎のオブジェクト定義)
 ・メンバ関数を与える複数のprototype-function()記述。prototype指定
  (クラス共通のメンバ関数定義)
からなります。
場合によっては、C++/Javaのstatic定義に当たる記述もあります。
 ・複数のstatic変数記述。クラス名.変数名=値;で指定
 ・複数のstatic関数記述。クラス名.関数名= function(引数){...}で指定
クラス全体を囲む記述はなく、色々な要素をばらばらに並べる形となります。

注意:
構築子の中で関数を定義してある説明を良く見かけますが、余程特殊な用途 でもないかぎり、決して行ってはなりません。
構築子で定義すると、クラスインスタンスをnewで生成する度に、同じ 手続きオブジェクト(プログラム実体)が繰り返し生成されます。

function pos(x,y){
   this.x= x==undefined? 0 : x;
   this.y= y==undefined? 0 : y;
   this.sub = function(that){ // NG!ここで定義してはならない
      return new pos(this.x-that.x , this.y-that.y);
      }
   this.abs = function(){     // NG!ここで定義してはならない
      return Math.sqrt(this.x*this.x + this.y*this.y);
      }
   }

要素記述法
クラス名、構築子、メンバ変数 次のような形式で定義します。

 function クラス名(構築引数){
   this.メンバ変数名 = 初期値;
   ...
   }

一見普通の関数定義ですが、作成されるオブジェクトを現すthisを使い、thisのメンバに値を セットするところが普通の関数との違いです。thisはJavascriptの普通のオブジェクト ですので適当な名前の要素をセットすることができます。
この形の関数(構築子)がある場合、キーワードnewを使った次の呼び出しでオブジェクトを生成できます。
生成されたクラスオブジェクトのメンバには".メンバ名"でアクセスできます。

 var 変数= new クラス名(引数);
 alert(変数.メンバ名); // メンバアクセス

関数 関数は次の形式で定義します。

 クラス名.prototype.関数名 = function(){
   // this.メンバ名でメンバアクセス
   ...
   }

prototypeというキーワードを使った特殊な記述をします。
構築子で関数をメンバとしてセットすることもできますが、構築子で 行うと、各クラスオブジェクト毎に同じ関数オブジェクトを生成してしまいます。
このprototype指定の場合は、ただ1個の関数オブジェクトを、 全ての同一クラスオブジェクトで参照する形となります。
構築子はクラスオブジェクト毎の定義で、prototypeはクラス共通の定義となります。
関数は、クラスオブジェクトに対して呼び出すことができます。

 var 変数= new クラス名(引数);
 変数.関数名(引数); // 関数呼び出し

スタティック関数 関数は次の形式で定義します。

 クラス名.関数名 = function(){
   // thisは使えない
   ...
   }

この形の関数はインスタンスを生成することなく使用できます。
 alert(クラス名.関数名(引数)); // 関数呼び出し

補足:static関数のみからなるクラスでも仮の構築子を置く必要が あります。直接は使用しません。
 function クラス名(){} //引数無子、中身無しの構築子
スタティック変数 基本的には関数定義と同じです.

 クラス名.変数名 = 初期値;

この形の変数はインスタンスを生成することなく使用できます。
 alert(クラス名.変数名);

 補足-1:javascriptのオブジェクトに関して

JavascriptのObjectは不定個のメンバを持つことができます。
各メンバには名前でアクセスできます。定義されていない名前の メンバに値を代入するとその時点でその名前のメンバが生成されます。

   var obj=new Object(); // 空オブジェクト生成
   obj.a=13;             // 新規メンバ追加
   alert(obj.a);         // メンバアクセス

Javascriptでは関数もObjectです。別オブジェクトの変数に 関数を設定することも可能です。

   var obj=new Object();  // 空オブジェクト生成
   obj.b= function(msg){  // 関数をメンバとして追加
      alert(msg);
      }
   obj.b("MESSAGE");      // メンバ(関数)呼び出し

関数の中でthisを用いれば、その関数の持ち主であるオブジェクトにアクセスできます。
this.メンバ名でメンバアクセスが可能となります。

   var obj=new Object();       // 空オブジェクト生成
   obj.a=13;                   // メンバa追加
   alert(obj.a);
   obj.b= function(){          // 関数b追加
      return "[a="+this.a+"]"; // 関数の中でメンバaにアクセス
      }
   alert(obj.b());             // 関数b呼び出し、戻り値表示

クラス定義はこれらの作業を少しまとまった形で行っているのです。

このことから想像は付くと思いますが、既に定義してあるクラスの関数や メンバも簡単に書き換えてしまうことができます。
Javaの「ゲッター、セッターによる愚かな隠蔽原理主義(かえってバグの元となり、かつ 効率を著しく悪くする)」など完全にすっとんでしまうレベル の柔軟さですね。(ただ、少しガードは欲しい)

 スタティック関数という言い方は????

定義される変数や関数を何と呼ぶかはかなり混乱しています。

この記事ではC++やJavaで使われる"スタティック変数、スタティック関数"という用語を 用いましたが、実際はダイナミックに生成され名前に結びつけられる訳で スタティックな訳ではありません。

関数の設置場所は3つあります。

  • 各オブジェクト毎(これは推奨しないやり方です)
  • クラスのprototypeのメンバ(普通の関数と言えます)
  • クラスメンバ(スタティック関数に相当します)
クラスのprototypeに置いた関数はクラスのインスタンス指定で呼び出すごく普通のクラス関数 となります。
クラスメンバに置いた関数はインスタンスと結び付けずクラス名.関数名で呼び出す関数となります。

この記事での用語の使い方はそのうち改める可能性もあります。

###

2011/7/14:スタティック変数、スタティック関数に関する記述追加

2013/5/6:番号付<pre>ブロックの番号がいつの間にか出なくなっていたので番号無し<pre>に変更

|

« ◇WEBページに行番号付きテキストを張りつける | トップページ | ココログ+firefox試験 »

トラックバック


この記事へのトラックバック一覧です: Javascriptでのクラスの作り方:

« ◇WEBページに行番号付きテキストを張りつける | トップページ | ココログ+firefox試験 »