オブジェクトとはその名の通り「物」のことです。現実世界には色々な物があります。例えば、はさみ、鉛筆、本などは「物」です。実際にはプログラムでは「状態」を変数で表し、「ふるまい」を関数(メソッド)で表すことになります。
そういった物には「状態」や「ふるまい」があります。例えば、鉛筆であれば、「状態」は線の色、色の濃さ、線の太さなどで、「ふるまい」は線が引けるなどです。
こういった物の「状態」や「ふるまい」をプログラムに持ち込んだものがオブジェクト指向です。
var date = new Date();
function Rectangle( w, h ){
this.width = w ; // 長方形の幅
this.height = h ; // 長方形の高さ
}
var r0 = new Rectangle( 2, 1 ); var r1 = new Rectangle( 4, 2 );
width,height を取り出すには次のようにします。
status = r0.width ; // 結果は 2// コンストラクタ関数の定義 function Rectangle( w, h ){ this.width = w ; // 長方形の幅 this.height = h ; // 長方形の高さ } // この関数がメソッドになる。 // 内部で this キーワードを使用していることに注意 function getArea_Rectangle(){ return this.width * this.height ; } // インスタンス生成 var r0 = new Rectangle( 3, 2 ); // メソッドの定義 r0.getArea = getArea_Rectangle ; // メソッドの呼び出し status = r0.getArea(); // 結果は 3*2 で 6
// コンストラクタ関数の定義 function Rectangle( w, h ){ this.width = w ; // 長方形の幅 this.height = h ; // 長方形の高さ } // この関数がメソッドになる。 // 内部で this キーワードを使用していることに注意 function getArea_Rectangle(){ return this.width * this.height ; } // メソッドの定義 Rectangle.prototype.getArea = getArea_Rectangle ; // インスタンス生成 var r0 = new Rectangle( 3, 2 ); var r1 = new Rectangle( 4, 6 ); // メソッドの呼び出し status = r0.getArea(); // 結果は 3*2 で 6 status = r1.getArea(); // 結果は 4*6 で 24
var r0 = new Rectangle( 3, 2 ); var r1 = new Rectangle( 4, 6 ); status = ( r0 == r1 );
var r0 = new Rectangle( 1, 1 ); var r1 = new Rectangle( 1, 1 ); status = ( r0 == r1 );
var r0 = new Rectangle( 1, 1 ); var r1 = r0 ; status = ( r0 == r1 );
var r0 = new Rectangle( 4, 3 ); var r1 = r0 ; r0.width = 5 ; status = r1.width ;
var r0 = new Rectangle( 4, 3 ); var r1 = new Rectangle( r0.width, r0.height ); r0.width = 5 ; status = r1.width ;
number,boolean,string)と参照型(object,array,function)の大きな違いですが、分かりましたでしょうか?
クラス:物の状態やふるまいを定義した箱(Rectangleなど)
インスタンス:クラスから生成(new)された実際のもの(r0,r1など)
インスタンス変数:インスタンス固有で持っている値(width,height など)
インスタンスメソッド:クラスのインスタンス全てで共有する関数(getArea など)
クラス変数:クラスそのものに関連付けられた変数(Math.PI など)
クラスメソッド:クラスそのものに関連付けられた関数(String.fromCharCode など)
メンバ:クラスの内部にある変数などの構成要素全体
Rectangle.SQRT2 = 1.414 ;
function Rectangle( w, h ){
this.width = w ; // 長方形の幅
this.height = h ; // 長方形の高さ
}
function getArea_Rectangle(){
return this.width * this.height ;
}
// インスタンスメソッドの定義
Rectangle.prototype.getArea = getArea_Rectangle ;
// この関数が Rectangle クラスのクラスメソッドになる
function getAreaMax_Static_Rectangle( p, q ){
return Math.max( p.getArea(), q.getArea() );
}
// クラスメソッドの定義
Rectangle.getAreaMax = getAreaMax_Static_Rectangle ;
// インスタンス生成
var r0 = new Rectangle( 3, 2 );
var r1 = new Rectangle( 4, 6 );
status = Rectangle.getAreaMax( r0, r1 ); // 結果は 24
function SuperClass(){
...
}
function SubClass(){
...
}
SubClass.prototype = new SuperClass ;
new SuperClass の後ろに括弧がないのは new SuperClass() と書いたのと同じで、new 演算子の特例です。引数がないときにこのように省略できます。
function SuperClass( p, q ){
this.p = p ;
this.q = q ;
}
function SubClass( p, q ){
this.constructor( p, q );
}
SubClass.prototype = new SuperClass ;
// これが Rectangle クラスの toString メソッドになる function toString_Rectangle(){ return "長方形 : "+this.width+"×"+this.height ; } function Rectangle( w, h ){ this.width = w ; this.height = h ; } Rectangle.prototype.toString = toString_Rectangle ; var r0 = new Rectangle( 3, 4 ); // 表示 status = r0 ; // 結果は????
function valueOf_Rectangle(){
return this.width*this.height ;
}
function Rectangle( w, h ){
this.width = w ;
this.height = h ;
}
Rectangle.prototype.valueOf = valueOf_Rectangle ;
var r0 = new Rectangle( 3, 4 );
status = r0-0 ; // 結果は 3*4-0 で 12
r0+"", valueOf メソッドを呼び出したいときは r0-0 などのようにするか、r0.toString() などのように明示的に記すしか方法はありません。
set,setWidth,setHeightgetWidth,getHeightequalsgetAreagetDigomax、小さい方を返す minscalehalftoArrayvalueOftoStringgetAveArea// コンストラクタの定義 // // ----- 宣言の形式 ----- // // new Rectangle() // width = height = 1.0 ; // // new Rectangle( Rectangle r ) // width = r.width, height = r.height ; // // new Rectangle( number n ) : おまけ // width = height = n ; // // new Rectangle( number w, number h ) // width = w, height = h ; function Rectangle(){ var a = arguments ; // 引数 // 引数の個数により、処理を分岐 switch( a.length ){ // 引数が0個のとき case 0 : default : this.width = this.height = 1.0 ; break ; // 引数が1つのとき case 1 : { // 引数の型が Rectangle if( a[0].constructor == Rectangle ){ this.width = a[0].width ; this.height = a[0].height ; }else{ this.width = this.height = a[0]; } break ; } // 引数が2つのとき case 2 : { this.width = a[0]; this.height = a[1]; break ; } } } // 関数内でメソッドを定義することにより、限りなくバッティングを減らすことが可能になる。 // この関数内でさらに関数を定義できるということにも注意。 // 今回、全てのメソッド定義には無名関数(関数リテラル)を使用している。 function setBasicMember__Rectangle__(){ var R = Rectangle ; var RP = R.prototype ; // メソッドが多い場合に便利 /************* クラスメソッド *************/ R.getAveArea = function(){ var s = 0 ; var a = arguments ; for(var i=0;i<a.length;i++) s += a[i].getArea(); return s/a.length ; }; /********** インスタンスメソッド **********/ RP.set = function(){ var a = arguments ; var r ; switch( a.length ){ case 0 : default : r = new Rectangle(); break ; case 1 : r = new Rectangle( a[0] ); break ; case 2 : r = new Rectangle( a[0], a[1] ); break ; } // 新しく生成し、そのインスタンスから値を参照する。 // このテクニックはファイルサイズを減らしたいとき有効 this.width = r.width ; this.height = r.height ; }; // 以下のようにメソッドに複数の名前を与えることも可能 RP.setWidth = RP.setW = function( w ){ this.width = ( w ? w : 1.0 ); }; RP.setHeight = RP.setH = function( h ){ this.height = ( h ? h : 1.0 ); }; RP.getWidth = RP.getW = function(){ return this.width ; }; RP.getHeight = RP.getH = function(){ return this.height ; }; // このようなクラスの場合、equals メソッドを定義しておくのが定石 RP.equals = function( r ){ return ( ( this.width == r.width ) && ( this.height == r.height ) ); }; RP.getArea = function(){ return this.width * this.height ; }; // 対角線の長さを求める式は √( width^2 + height^2 ) RP.getDigo = function(){ return Math.sqrt( Math.pow( this.width, 2 )+Math.pow( this.height, 2 ) ); }; RP.max = function(){ return Math.max( this.width, this.height ); }; RP.min = function(){ return Math.min( this.width, this.height ); }; RP.scale = function( v ){ this.width *= v ; this.height *= v ; }; // 他メソッドをメソッド内で使用することも勿論、可能 RP.half = function(){ this.scale( 0.5 ); }; RP.toArray = function(){ return new Array( this.width, this.height ); }; RP.valueOf = function(){ return ( this.width == this.height ); }; RP.toString = function(){ return "Rectangle : "+this.width+" × "+this.height ; }; } setBasicMember__Rectangle__(); // 関数の呼び出し