オブジェクトとはその名の通り「物」のことです。現実世界には色々な物があります。例えば、はさみ、鉛筆、本などは「物」です。実際にはプログラムでは「状態」を変数で表し、「ふるまい」を関数(メソッド)で表すことになります。
そういった物には「状態」や「ふるまい」があります。例えば、鉛筆であれば、「状態」は線の色、色の濃さ、線の太さなどで、「ふるまい」は線が引けるなどです。
こういった物の「状態」や「ふるまい」をプログラムに持ち込んだものがオブジェクト指向です。
var date = new Date();の date は Date クラスのインスタンスということになります。
function Rectangle( w, h ){ this.width = w ; // 長方形の幅 this.height = h ; // 長方形の高さ }これで Rectangle クラスのコンストラクタ関数は定義できました。
var r0 = new Rectangle( 2, 1 ); var r1 = new Rectangle( 4, 2 );これで r0 と r1 は Rectangle クラスのインスタンス(オブジェクト)になりました。
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 で 24prototype で追加されたメソッドは全インスタンスで共有(に継承)されます。
var r0 = new Rectangle( 3, 2 ); var r1 = new Rectangle( 4, 6 ); status = ( r0 == r1 );これは、予想通り false が表示されます。では、次はどうでしょう。
var r0 = new Rectangle( 1, 1 ); var r1 = new Rectangle( 1, 1 ); status = ( r0 == r1 );true が返されると思いますか?
var r0 = new Rectangle( 1, 1 ); var r1 = r0 ; status = ( r0 == r1 );これは true が表示されます(これは参照している場所が一緒のためにこうなります)。
var r0 = new Rectangle( 4, 3 ); var r1 = r0 ; r0.width = 5 ; status = r1.width ;答えは 4 ではなく、5 です。
var r0 = new Rectangle( 4, 3 ); var r1 = new Rectangle( r0.width, r0.height ); r0.width = 5 ; status = r1.width ;こうしておけば、ステータスバーに表示されるのは 4 です。
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 ;prototype オブジェクトって便利ですね(笑)
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 ;constructor 関数を使用すればこのように簡潔にかけます(Javaのsuperみたいに使用してます)。 constructor 関数は作成元の関数を返すので、これを見ると prototype プロパティの働きが少しは分かるのではないでしょうか。
// これが 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-0 を付加しているのはこれが数であることを明示的にするためです。toString メソッドと valueOf メソッドのどちらが呼び出されるかは用途によって違います。toSring メソッドを呼び出したいときは
r0+""
, valueOf メソッドを呼び出したいときは r0-0
などのようにするか、r0.toString()
などのように明示的に記すしか方法はありません。
set,setWidth,setHeight
getWidth,getHeight
equals
getArea
getDigo
max
、小さい方を返す min
scale
half
toArray
valueOf
toString
getAveArea
// コンストラクタの定義 // // ----- 宣言の形式 ----- // // 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__(); // 関数の呼び出しユーザ定義オブジェクトの作成例については Class Library のページもあるので、そちらも参考にして下さい。