カテゴリー
オライリーJavaScript

モジュール

一般的に、モジュールは、JavaScriptコードを1つのファイルにまとめたもの。
モジュールの目的は、さまざまな場所から持ってきたコードを組み合わせて、
大きなプログラムを作成できるようにすること。

カテゴリー
オライリーJavaScript

サブクラスの定義

例:

B.prototype = inherit(A.prototype); //サブクラスはスーパークラスから継承する
B.protoyupe.constructor = B;    //継承したconstructorプロパティを上書きする
カテゴリー
オライリーJavaScript

サブクラス

オブジェクト指向プログラミングでは、クラスAからほかのクラスBを拡張できる。
このような場合、Aをスーパークラス、Bをサブクラスを呼ぶ。
BのインスタンスはAのインスタンスメソッドをすべて継承する。
クラスBには、独自のインスタンスメソッドを定義できる。
クラスAで定義されている同名のメソッドをオーバーライドしても構わない。
メソッドチェーン
コンストラクタチェーン

抽象クラス
実装のないメソッドを定義しているクラス
これらの抽象メソッドは、抽象クラスの具象サブクラス側で実現する。

サブクラスを作成するときに重要なことは、プロトタイプオブジェクトを適切に初期化すること。

サブクラスの代わりに使われる合成

カテゴリー
オライリーJavaScript

コンストラクタオーバーロードとファクトリメソッド

コンストラクタオーバーロード
渡された引数によって、初期化の方法を変更する。
コンストラクタは、クラスの窓口になるもの。
クラスごとに1つしかないのが普通。

ファクトリメソッド
クラスのインスタンスを返すクラスメソッドのこと。
好きな名前を付けられる。
メソッドの名前を変えれば、初期化の方法を変えることができる。

カテゴリー
オライリーJavaScript

プライベートな状態

古典的なオブジェクト思考プログラミングでは、
一般的にオブジェクトの状態をオブジェクト中にカプセル化する(隠す)ことが目的になる。
つまり、状態をアクセスするときは、必ずオブジェクトのメソッドを使うようにして、
重要な状態変数直接読んだり、書き込んだりできないようにする。
Javeなどでは、クラスのインスタンスプロパティに対してprivate宣言できる。

インスタンスを生成するコンストラクタ呼び出しのクロージャー中に閉じ込められた変数(または引数)を使えば、
プライベートインスタンスプロパティをほぼ実現できる。
このために、コンストラクタ中に、関数を定義する。
この関数から、コンストラクタの引数や変数にアクセスできる。
そして、定義した関数を新たに生成したオブジェクトのプロパティに代入する。

カテゴリー
オライリーJavaScript

比較用のメソッド

JavaScriptの等値演算子は、オブジェクトに対して、値による比較ではなく、参照による比較を行う。
つまり、2つのオブジェクトがおなじプロパティ名や値を持つかどうかを比較するのではなく、
2つのオブジェクト参照が同じオブジェクトを参照しているかどうかを比較する。

カテゴリー
オライリーJavaScript

列挙型

型を定義するとき、ある有限個の値のリストを持つような型のことを列挙型という。
C言語などでは、enumキーワードを使って列挙型を宣言する。

カテゴリー
オライリーJavaScript

constructorプロパティ

オブジェクトのクラスを識別する方法に、constructorプロパティを使う方法

function typeAndValue(x) {
     if(x == null) return "";        //null と undefined はコンストラクタをもたない
     switch(x.constructor) {
         case Number: return "Number: " + x;     //基本型にタウする処理
         case String: return "String: '" + x + "'";
         case Date: return "Date: " + x;             //次は、組み込み型に対する処理
         case RegExp: return "Regexp: " + x;
         case Complex: return "Complex: " + x;   //最後に、ユーザー定義の型に対する処理
     }
 }

constructorプロパティを使う方法には、instanceof演算子を使う方法と同じ問題がある。
ブラウザウィンドウに複数のフレームがある場合など、複数の実行コンテキストで値を共有している場合は、うまく動きません。
この状況では、フレームごとにコンストラクタ関数がある。
例えば、あるフレームのArrayコンストラクタは、別のフレームのArrayコンストラクタとは同じではない。

また、JavaScriptでは、すべてのオブジェクトがconstructorプロパティを持つわけではない。

カテゴリー
オライリーJavaScript

instanceof演算子

instanceof演算子
左にオブジェクト、右にクラスのコンストラクタ関数を指定する。

    o instanceof c

オブジェクト o が、c.prototype を継承する場合は true になる。
直接継承していなくても良い。

クラスが同一かどうかの窓口はコンストラクタですが、同一かどうかを判断する基準はプロトタイプです。
instanceof演算子では、コンストラクタ関数を使うが、この演算子で本当にテストしているのは、
オブジェクトが何を継承しているかです。
どのコンストラクタを使ってオブジェクトが生成されたかどうかではない。

ある特定のプロトタイプオブジェクトに対して、オブジェクトのプロトタイプチェーンに含まれているかを調べたいときに、
コンストラクタ関数を使いたくない場合には、
isPrototypeOf()メソッドが使える。

example 9-1 range:値の範囲を表すクラス

//新しいrangeオブジェクトを返すファクトリ関数
function range(from, to) {
	//inherit()関数を使って、プロトタイプオブジェクト(この後で定義)を
	//継承するオブジェクトを生成する。
	//プロトタイプオブジェクトは、この関数のプロパティに保存する。
	//すべてのrangeオブジェクトで
	//共有するメソッドを定義する
	var r = inherit(range.methods);

	//新しいrangeオブジェクトの始端と終端を保存する
	r.from = from;
	r.to = to;

	//最後に新しいオブジェクトを返す
	return r;
}

//このプロトタイプオブジェクトで定義したメソッドは全rangeオブジェクトで継承する
range.methods = {
	//xが範囲内であればtrueを返し、範囲外であればfalseを返す
	//このメソッドは数値だけでなく、文字列やDateオブジェクトでも動作する
	includes: function(x) { return this.from <= x && x <= this.to },

	//範囲中に含まれる各整数に対して、一度ずつfを呼び出す
	//このメソッドは数値に対してしか動作しない
	foreach: function(f) {
		for (var x = Math.ceil(this.from); x < <= this.to; x++) f(x);
	},

	//rangeオブジェクトの文字列表現を返す
	toString: function() { return "(" + this.from + "..." + this.to + ")"}
};

//rangeオブジェクトの使用例
var r = range(1,3);			//新しいrangeオブジェクトを生成
r.includes(2);				//true: 2は範囲内
r.foreach(console.log);		//1 2 3 を出力する
console.log(r);				//(1...3)を出力する

上記のrangeクラスのメンバかどうかを調べるには次のようなメソッドを記述します。

range.methods.isProtoptypeOf(r);        //range.methods はプロトタイプオブジェクト

instanceod演算子とisPrototypeOf()メソッドの問題点は、あるオブジェクトのクラスを調べられないことです。
調べられるのは、あるオブジェクトがクラスのメンバがどうかだけ。

クライアントサイドJavaScriptでは、さらに、
Webアプリケーションでは、複数のウィンドウやフレームを使い、ウィンドウやフレームごとに実行コンテキストが異なる。
つまり、ウィンドウ、フレームごとに、グローバルオブジェクトを持ち、コンストラクタ関数を持つ。
2つの異なるフレームで生成された2つの配列は、別のフレームArray()コンストラクタに対して、
instanceof演算子を使ってもtrueにならない。

カテゴリー
オライリーJavaScript

クラスと型

JavaScriptの型
null
undefined
論理値
数値
文字列
関数
オブジェクト
は、typeof演算子を使うことで判定できる

しかし、オブジェクトのクラスを識別できた方が、一般的には便利。

任意のオブジェクトのクラスを判定する3つの方法
instanceof演算子を使う方法
constructorプロパティを使う方法
コンストラクタ関数の名前を使う方法