* クラスの作り方 - 関数オブジェクトを使って [#ee1faea0]
** クラスを作成 [#u48ec2eb]
*** 空のコンストラクタ [#ga5b2288]
var Animal = function() {};
関数オブジェクトをクラス(のコンストラクタ)に見立てる。
*** コンストラクタでメソッドやフィールドを定義[#fc448499]
thisを使ってクラスのプロパティにアクセスする。
var Animal = function(name) {
this.name = name;
this.getName = function() {
console.log('NAME: ' + this.name);
};
};
ただし、この方法はインスタンス生成ごとにメソッドを定義する事になり、メモリ効率が悪い。これを避けるには、↓のようにプロトタイプによるメソッドやフィールドを定義を行う。
*** プロトタイプでメソッドを定義[#n7668f55]
var Animal = function(name) {
this.name = name;
};
Animal.prototype = {
getName: function() {
console.log('NAME: ' + this.name);
}
};
:プロトタイプ汚染|この方法でArrayのような組込みクラスを拡張する事が可能だが、安易に拡張するとfor inでオブジェクトのプロパティを列挙すると拡張したプロパティ(メソッド)と元のプロパティ(メソッド)が混ざってしまう(プロトタイプ汚染)ので注意が必要。
*** フィールドもプロトタイプに乗せたい場合 [#zca9d352]
var Animal = function(name) {
this.init.apply(this, arguments);
};
Animal.prototype.init = function (name) {
this.name = name;
};
初期化メソッドinit()を作って、コンストラクタではそれをapplyで呼ぶだけにする。
** インスタンスを生成・メソッドを利用 [#m5dce2e9]
var a = new Animal('taro');
a.getName();
** 継承 [#w1db1e89]
*** 親クラス作成 [#ac0cfa4d]
var Animal = function(name) {
this.name = name + '(Animal)';
};
Animal.prototype = {
getName: function() {
console.log('NAME: ' + this.name);
}
};
*** 子クラス作成 [#q7f19729]
var Human = function(name, age) {
this.name = name + '(Human)';
this.age = age + '(Human)';
};
*** 親クラスを継承 [#ae15c212]
Human.prototype = new Animal;
なお、↑のままではHumanクラスのprototypeのconstructorプロパティはAnimalなので、これをHumanにする場合は↓のようにする。
Human.prototype = new Animal;
Human.prototype.constructor = Human;
*** 子クラスにメソッドを定義 [#ydf071ca]
Human.prototype.getAge = function () {
console.log('AGE: ' + this.age);
}
*** 子クラスのインスタンスを作成・メソッドを利用 [#y877eb40]
var h = new Human('jiro', 15);
h.getName();
h.getAge();
*** 子クラスで親クラスのコンストラクタメソッドを利用 [#g1656bf5]
var Human = function(name, age) {
Animal.call(this, name);
this.age = age + '(Human)';
};
var h = new Human('jiro', 15);
h.getName();
親クラスであるAnimalを明示して、call()を使う。
** プロトタイプ [#oba0abba]
*** プロトタイプチェイン [#efb4d835]
メソッドの検索は次の順で行われる。
- h.say()
- Human.prototype.say()
- Animal.prototype.say()
- Object.prototype.say()
親クラスを辿って行き、最終的にObject.prototypeで見つからなければ、終了する。
*** プロトタイプ継承の注意点 [#fbdffe52]
継承のために、
Human.prototype = new Animal;
ではなく、
Human.prototype = Animal.prototype;
としてはならない。この場合、HumanのprototypeはAnimalのprototypeを参照する事になるので、
Human.prototype.foo = function () { console.log('foo()'); };
のようにHumanにメソッドを追加すると、Animalにもメソッドが追加されてしまう。
var a = new Animal();
a.foo(); // 本来、未定義であるべき
** JavaScriptのクラス(オブジェクト)の問題点 [#e4ecfe17]
- 親クラスのコンストラクタ(メソッド)を呼び出すのが難しい。
- 多重継承が難しい。
これらを解決するには、何らかのライブラリを使うのが妥当。
** 参考 [#ie9c838e]
:Defining classes and inheritance | http://prototypejs.org/learn/class-inheritance
:A Base Class for JavaScript Inheritance | http://dean.edwards.x/weblog/2006/03/base/
:Simple JavaScript Inheritance | http://ejohn.org/blog/simple-javascript-inheritance/