JavaScript 第5版 9章 クラスとコンストラクタとプロトタイプ

7月 26th, 2009 by t32k | Filed under javascript.

JavaScriptはJavaやC#が持つような通常のクラスをサポートしないがコンストラクタ関数やプロトタイプオブジェクトを使用してクラスをシュミレートできる。

9.1 コンストラクタ

コンストラクタ関数は単にコンストラクタとも呼ぶ
新しく生成されたオブジェクトに対してプロパティに値を設定するなど初期化を行いオブジェクトを使えるようにする。

//コンストラクタ定義、thisの使い方が肝function Rectangle(w, h) { this.width = w; this.height = h;}

//コンストラクタを呼び出してオブジェクトを生成var rect1 = new Rectangle(2,4); // rect1 = {width:2, height:4 };

コンストラクタが引数を使ってthisキーワードで参照するオブジェクトのプロパティを初期化する部分、要チェックやで!

9.2 プロトタイプと継承

関数を呼び出すときに使われたオブジェクトがthisキーワードの値になる

funciton computeAreaOfRectangle(r) { return r.width * r.height; }

関数にオブジェクトを引数として渡すのではなく、
オブジェクトに対してメソッドを呼び出すのがオブジェクト指向的↓

function Rectangle(w, h) {this.width = w;this.height = h;this.are = function()  { return r.width * r.height; }}

var r = new Rectangle(8.5, 11);var a = r.area();

すべてのJavaScriptオブジェクトはプロトタイプオブジェクトへの参照が含まれる
JavaScriptオブジェクトはプロトタイプからプロパティを継承する

//すべてのインスタンスで共有するプロパティについてはプロトタイプオブジェクトに追加Rectangle.prototype.area = function() { return this.width * this.height; }

コンストラクタで初期化されたすべてのオブジェクトはコンストラクタに関連づけられたプロトタイプオブジェクトからまったく同じプロパティを継承
プロトタイプオブジェクトはメソッドや定数プロパティを定義するのに理想的

プロトタイプオブジェクトを使用するとたくさんのオブジェクトがプロパティを継承し共有できるので使用するメモリを大幅に節約できる
あるオブジェクトを生成した「後に」そのオブジェクトのプロトタイプにプロパティを追加した場合でもそのプロパティを継承する。つまり既存のクラスに新たにメソッドを追加することも可能だが、あまり良い考えではない

継承プロパティへのアクセス
例えば、オブジェクトoのプロパティpを呼び出すときにJavaScriptは最初にオブジェクトoにプロパティpがあるかどうかチェックして、無かった場合次にオブジェクトoのプロトタイプオブジェクトにプロパティpがあるかどうかチェックする
オブジェクトoにプロパティpを設定すると新しいプロパティpが生成されオブジェクトoに直接格納される。この場合プロトタイプオブジェクトのプロパティpは読み出されることはない(先にオブジェクトoのプロパティを探すから)

組み込み型の拡張
StringやDateなどの組み込みクラスを拡張することも可能
でもあんまりやらない方が賢明(めんどくさいから)
Object.prototypeには絶対プロパティを追加するな!
Webブラウザなどのホストオブジェクトにはコンストラクタやプロトタイプを持たないので拡張できない
一般的に組み込み系クラスは拡張すべきではないが古くて標準に準拠しないJavaScript実装に標準のメソッドを追加するのは便利(IE4,5で対応していないFunction.apply()の追加など)

9.3 JavaScriptの「クラス」

オブジェクト:名前の付けられた様々なデータを保持するデータ構造のこと
クラス:オブジェクトの構造を定義したもの

Javaの表記法でクラス名の先頭を大文字にし、オブジェクトを小文字するのが一般的
JavaScriptでもこの表記法が便利

インスタンスプロパティ
オブジェクトごとにそれぞれ異なる専用のインスタンスプロパティがある
Rectangleオブジェクトのプロパティwidthがインスタンスプロパティに相当する
JavaScriptのオブジェクトプロパティはデフォルトでインスタンスプロパティになる

クラスプロパティ
Javaの場合、クラスそのものに関連づけられたプロパティのことをクラスプロパティという
JavaScriptでクラスプロパティをシミュレートするにはコンストラクタ関数自身のプロパティを定義

Rectangle.UNIT = new Rectangle(1,1);

インスタンスメソッド
インスタンスメソッドは特定のオブジェクトを介して呼び出す
thisキーワードを使って処理対象のオブジェクト(インスタンス)を参照
クラスの全てのインスタンスで共有される

a = r.area();

クラスメソッド
クラスに関連したメソッド
Date.parse()メソッドなどが例
コンストラクタオブジェクトを介して呼び出す
よく掴めない><

Circleクラスの例

//コンストラクタ生成function Circle(radius) { this.r = radius; // インスタンスプロパティ}

Circle.PI = 3.14159; // クラスプロパティ//インスタンスメソッドCircle.prototype.area = function() { return Circle.PI * this.r * this.r; }

//クラスメソッドCircle.max = function(a, b) { if(a.r > b.r) return a; else return b;}

プライベートメンバ
プライベートとして宣言することでそのプロパティはクラスのメソッドからのみアクセス可能となる
データカプセル化では特別なアクセッサーメソッドからしかアクセスできないようにする
よくわからんて><

9.4 オブジェクト共通メソッド

toString()メソッド
クラス専用の文字列表記を持つために定義する
オブジェクトに関する情報を変換した文字列を含めればデバッグにも役立つ

valueOf()メソッド
オブジェクトを文字列以外の基本型に変換するときに呼び出される
(大抵数値が多い)

比較用のメソッド
JSの等値演算子はオブジェクトに対して「値による」比較ではなく「参照による」比較を行う
2つのオブジェクト参照が同じオブジェクトを参照しているかどうか比較する
参照が等しいかどうかだけでなく、値として2つのオブジェクトが等しいかどうかや2つのオブジェクトの大小を比較できると便利な場合がある
まぁよくわからんね><

9.5 スーパクラスとサブクラス

JavaやC++などのオブジェクト指向言語にはクラス階層という明確な概念がある
JSはクラスベースの継承ではなくプロトタイプベースの継承をサポート
Objectクラスがスーパクラスにあたり、そのほかのクラスはサブクラスと見なせる

コンストラクタチェーン
明示的にスーパークラスのコンストラクタ関数を呼び出すこと

オーバライドされたメソッドの呼び出し
サブクラスでスーパークラスのと同じ名前のメソッドを定義するとサブクラスはそのメソッドをオーバライド(上書き)する
いわゆるメソッドチェーン

9.6 継承以外のクラス拡張方法

あるクラスから別のクラスへメソッドをコピーするこができる
他のクラスから利用されるメソッドを定義するクラスのことをミックスインクラスと呼ぶ

9.7 オブジェクトクラスの判定

JSは弱い型付きのプログラミング言語
基本データ型とオブジェクトを区別するにはtypeof演算子が便利
instanceof演算子でさらに詳細な情報も調べられる
組み込みオブジェクトにはtoString()メソッドが便利

ダックタイピング
アヒル(duck)のように歩いて、アヒルのようにガーガー鳴くなら、それはアヒルである
あるオブジェクトが、あるクラスで定義されているメソッドを全て実装していれば、そのオブジェクトはそのクラスのインスタンスである
つまりあるクラス(A)のコンストラクタ関数で生成されなくてもAのプロパティを持っていればXはクラスAのインスタンスとして扱うことができる


Comments are closed.