JavaScriptのクラス定義(プロトタイプベースのオブジェクト指向言語)

JavaScriptにおける“クラス”の定義は、次のように書きます。Fruitクラスの定義例です。
var Fruit = function() { };
上記のfunctionは、new で Fruitクラスを生成するときに実行するものです。 その意味では、コンストラクタと呼んでもよいでしょう。
これを利用して、生成したFruitオブジェクトをalertで表示させている例を下に示します。
var apple = new Fruit();
alert(apple);
以下では引数があるコンストラクタとプロパティ、メソッドを用意した例です。

インスタンス化されたオブジェクトに対しても、 後からメンバを追加できるのがJavaScriptの特徴で、 これをJavaScriptの「動的性質」と呼ばれます。
以下に、上記を書き直して、動的性質を利用そて後からalertメソッドを追加した例を示します。
var Fruit = function(name,price) { 
	this.name=name;
	this.price=price;
	this.toString=function(){
		return this.name+"は"+this.price+"円";
	};
};
var apple=new Fruit("りんご", 130);
apple.alert=function(){
	alert(this.toString());
};
これで、apple.alert();と実行できます。 しかし インスタンスに追加したメンバは、オブジェクト共通ではなく そのインスタンスのみで有効です。
よってこの後で、次のように書くと 「オブジェクトでサポートされていないプロパティまたはメソッドです。」のようなエラーメッセージが出るでしょう。
mikan=new Fruit("みかん", 50);
mikan.alert();

つまり、インスタンス共通のメソッドを定義するには、インスタンスに対してではなく、 コンストラクタ内で定義する必要があるというわけです。
こうすると、インスタンス内の各メソッドごとに、メソッド参照するための記憶領域が用意されことが分かります。
(これにより、特定のインスタンスのメソッドの置き換えを可能にしています。)

プロトタイプ・ベースのオブジェクト指向

上記例で示したようにコンストラクタ内で作ったtoStringやalertの関数を参照する変数は、 インスタンスごとにその記憶域が存在します。
これは、メモリの節約から考えると 良い方法ではないでしょう。
さて、それを回避する方法がprototypeを使った 関数定義で、その例を以下に示します。

var Fruit = function(name,price) { 
	this.name=name;
	this.price=price;
};
Fruit.prototype.toString=function(){
	return this.name+"は"+this.price+"円";
};
Fruit.prototype.alert=function(){
	alert(this.toString());
};

この場合、各インスタンスは、共通のprototypeという領域を参照することで toStringや、alertメソッドが実行されます。
この、各インスタンス共通のprototypeを使うことから、 メモリの節約もできるという訳です。
なお、先に述べたインスタンス内に関数を参照する変数も使えます。
この変数に関数を割り当てた場合と、prototypeの関数の両方を持つ場合は、 どちらが動作するのでしょうか? 次のような例の場合です。

var Fruit = function() {
	this.alert=function(){
		alert("ミカン");
	};
};
Fruit.prototype.alert=function(){
	alert("りんご");
};
var a=new Fruit();
var b=new Fruit();
delete b.alert;	//bのalert変数を削除(prototypeのalertは残っている)
a.alert();		//ミカンの表示
b.alert();		//りんごの表示

上記のa.alert()の実行は、コメントで示したミカンが表示される。つまりインスタンス内の変数が優先されるということです。
上記で使っている delete命令はオブジェクトを削除する命令です。 delete b.alertよって、インスタンス内の変数が無くなることによりprototype.alertが実行されて、りんごの表示がでます。
以上より分かるように、実行する関数が検索される順番は、インスタンス内の関数変数、次にprototypeの関数変数ということにです。
なお delete演算子ではなく、インスタンス側のプロパティにundefined(未定義)値を設定するとどうなるでしょうか?
上記の delete b.alert; b.alert= undefined;  とすると 実行エラーが起きるでしょう。この場合はインスタンス内の関数変数が削除されたのではなく、存在したまま記憶内容が未定義になり、 未定義の関数を実行したためにエラーが発生しているのです。

なお、上記でりprototypeに関数を参照する変数を指定した例を示していますが、これは単なる情報を記憶した場合の動作も同じです。 以下に例を示します。

var Fruit = function() {
	this.data="ミカン";
};
Fruit.prototype.data="りんご";
var a=new Fruit();
var b=new Fruit();
delete b.data;	//bのdata変数を削除(prototypeのdataは残っている)
alert(a.data);	//ミカンの表示
alert(b.data);	//りんごの表示

プロトタイプをオブジェクト・リテラルで定義する

リテラルとは、任意の式内で直接に記述可能なデータ表現のことです。
JavaScriptでは、連想配列(ハッシュ)のオブジェクト・リテラルの表現方法で、 {名前1 : 値1,名前2 : 値2,名前3 : 値3, ……} という表記があります。
{} で 変数とその設定値を挟みます。この時、変数と設定値の間に:を付けます。 そして,で区切って並べる表現です。 この表現を利用して、prototypeに関数を設定する例を示します。

var Fruit = function(name,price) { 
	this.name=name;
	this.price=price;
};
Fruit.prototype={
	toString:function(){
		return this.name+"は"+this.price+"円";
	},
	alert:function(){
		alert(this.toString());
	}
};

プロトタイプ・チェーン(プロトタイプ・ベースのオブジェクト指向における継承機構)

以下で、Fruitを継承したSpecialFruitのインスタンスの動作例を示します。

var Fruit = function(name,price) { 
	this.name=name;
	this.price=price;
};
Fruit.prototype={
	toString:function(){
		return this.name+"は"+this.price+"円";
	},
	alert:function(){
		alert(this.toString());
	}
};
var SpecialFruit = function() {};
SpecialFruit.prototype=new Fruit("青森りんご",180);
var apple=new SpecialFruit();
apple.alert();//「青森りんごは180円」の表示
SpecialFruit.prototype.toString=function(){
	return this.price+"円で"+this.name+"を買えます。";
};
apple.alert();//「180円で、青森りんごが買えます。」の表示

プロトタイプ・オブジェクト(SpecialFruit.prototype)にFruitクラスのインスタンスを格納しているという点に 注目してください。 これによって、SpecialFruitクラスのインスタンスでは、Fruitクラスのalertメソッドを呼び出すことが可能です。
そして、動的に振る舞いを変更することができます。
上記の例では、途中でtoStringのメソッドを変更することで、alertの動作を変更しています。

このように、JavaScriptではプロトタイプにインスタンスを設定することで、インスタンス間の継承関係を形成することができます。
もちろん、この継承関係はさらに多階層にすることも可能で、その場合にも順に階層をさかのぼって、 最上位のObject.prototypeに行き当たるまでメンバの検索が行われることになります。


補足説明
上記もオブブジェクト・リテラルでprototypeの設定例を示しました。
実はJavaScriptにおいて、オブジェクトと連想配列との間に厳密な区別はありません。 つまり、オブジェクトと連想配列は、JavaScriptの世界においては同一の概念なのです。
よって次の左右の記述は、意味的に完全に同じです。

var obj = new Object();
obj.x = 1;
obj.y = 2;
var obj = {x:1, y:2};


上記において、obj.xの表現は、連想配列のアクセス方法で行うと obj["x"]となり、両者は同じことです。
なお、コンストラクタを用意しなくても、簡単なインスタンスであれば、 オブブジェクト・リテラルの表現で生成できます。
その例を以下に示します。

var apple = {
	name: "りんご",
	price: 130,
	alert: function() {
    		alert(this.name+"は"+this.price+"円");
	}
};
apple["alert"](); //apple.alert(); と同じです。

自作乱数クラスの例