文書の過去の版を表示しています。
クラス
JavaScriptにはクラスはないが、関数オブジェクトをコンストラクタとして呼び出すことができる。
Functionオブジェクト
関数を定義すると、新しい Function オブジェクトが作成されます。
function ClassA(){ } window.alert(ClassA instanceof Function); // true
クラスを定義とインスタンス作成
Functionオブジェクトに演算子 new を使うと新しいインスタンスを作成できます。Function オブジェクトはコンストラクタとして働きます。
function MyClass(){ } var my = new MyClass(); window.alert(my instanceof MyClass); // true window.alert(my.constructor == MyClass); // true
インスタンス my の constructor プロパティは 関数オブジェクト MyClass となり、my は MyClass のインスタンスとみなされます。
メソッド定義
コンストラクタは prototype プロパティを持っており、 prototype に関数オブジェクトをセットすることで、インスタンスのメソッドとなります。
function MyClass(){ } MyClass.prototype.execute = function () { window.alert("hoge"); }; var my = new MyClass(); my.execute(); // hogeと表示 var my2 = new MyClass(); my2.execute(); // hogeと表示
インスタンスに直接メソッドを付加することもできます
// インスタンス自身にメソッドを定義 my.execute2 = function () { window.alert("fuga"); }; my.execute2(); // fugaと表示 my2.execute2(); // my2はメソッドexecute2を持たないのでエラー
プロトタイプチェイン
メソッドを呼び出すと、まずインスタンス自身が呼び出されたメソッドを持っていないかチェックし、持っていればそれを実行します。
function Hoge() { } var hoge = new Hoge(); hoge.execute = function() { alert("あ") }; hoge.execute(); // "あ"と表示される
インスタンス自身がメソッドをもっていない場合は、コンストラクタのprototypeからメソッドを探して呼び出します。
function Fuga() { } Fuga.prototype = hoge; var fuga = new Fuga(); fuga.execute(); // プロトタイプ(hoge)のexecuteメソッドが呼ばれ、"あ"と表示される。
コンストラクタのprototypeもメソッドを持っていない場合は、prototypeオブジェクトのコンストラクタのprototypeを探して呼び出します。
function Piyo() { } Piyo.prototype = new Fuga(); var piyo = new Piyo(); piyo.execute(); // プロトタイプ(Fugaのインスタンス)のプロトタイプ(hoge)の execute メソッドが呼ばれ、"あ"と表示される。
このようにプロトタイプをさかのぼってメソッドを探す仕組みをプロトタイプチェインと呼びます。
プロパティの定義
代入式を実行した時点でプロパティが生成されるのでプロパティを宣言をする必要はありません。
function MyClass(){ this.hoge = "ホゲ"; // プロパティhogeが生成 } MyClass.prototype.printHoge = function () { print(this.hoge); } MyClass.prototype.printFuga = function () { print(this.fuga); } MyClass.prototype.setMohe = function (mohe) { this.mohe = mohe; } var my = new MyClass(); my.printHoge(); my.fuga = "ふが"; my.printFuga(); my.setMohe("モゲ"); print(my.mohe);
メソッドやプロパティは全て外部から自由にアクセス可能。内部表現の隠蔽は難しい(できなくはない…)
クラス定義
最近では prototype にメソッドを一つずつセットしていくよりも、prototypeプロパティそのものを書き換えてしまうことが多い。このときinitializeというメソッドを定義して、コンストラクタで呼び出す作法が一般的。
function MyClass(arg){ this.initialize(arg); } MyClass.prototype = { initialize: funtion(arg) { this.hoge = arg; } printHoge: function() { print(this.hoge); }, printFuga: function () { print(this.fuga); }, setMohe: function (mohe) { this.mohe = mohe; } }; var my = new MyClass("ほげ"); my.printHoge(); my.fuga = "ふが"; my.printFuga(); my.setMohe("モゲ"); window.alert(my.mohe);
無名関数からクラスを生成
無名関数もコンストラクタになる。
var MyClass = function(arg) { this.initialize(arg); } MyClass.prototype = { initialize: function(arg) { this.hoge = arg; }, inspect: function() { print(this.prototype); print(this.constructor); for (var i in this) { print (i + "=" + this[i]); } } } var my = new MyClass(1000); my.fuga = "fugafuga"; my.inspect();