- バックアップ一覧
- 差分 を表示
- 現在との差分 を表示
- ソース を表示
- JavaScript/OOP/クラスの作り方/関数オブジェクトを使ったクラス作成 - 応用 へ行く。
- 1 (2009-06-07 (日) 12:09:53)
- 2 (2009-10-10 (土) 18:07:01)
- 3 (2009-11-09 (月) 12:07:31)
- 4 (2009-11-09 (月) 16:42:49)
- 5 (2011-01-26 (水) 21:42:21)
- 6 (2011-07-14 (木) 20:20:16)
- 7 (2011-07-15 (金) 14:49:59)
- 8 (2011-07-26 (火) 02:26:48)
- 9 (2012-02-13 (月) 06:48:17)
- 10 (2012-07-24 (火) 16:14:12)
- 11 (2012-07-28 (土) 06:55:52)
クラスの作り方 - 関数オブジェクトを使って
クラスを作成
空のコンストラクタ
var Animal = function() {};
関数オブジェクトをクラス(のコンストラクタ)に見立てる。
コンストラクタでメソッドやフィールドを定義
thisを使ってクラスのプロパティにアクセスする。
var Animal = function(name) { this.name = name; this.getName = function() { console.log('NAME: ' + this.name); }; };
ただし、この方法はインスタンス生成ごとにメソッドを定義する事になり、メモリ効率が悪い。これを避けるには、↓のようにプロトタイプによるメソッドやフィールドを定義を行う。
プロトタイプでメソッドを定義
var Animal = function(name) { this.name = name; }; Animal.prototype = { getName: function() { console.log('NAME: ' + this.name); } };
- プロトタイプ汚染
- この方法でArrayのような組込みクラスを拡張する事が可能だが、安易に拡張するとfor inでオブジェクトのプロパティを列挙すると拡張したプロパティ(メソッド)と元のプロパティ(メソッド)が混ざってしまう(プロトタイプ汚染)ので注意が必要。
フィールドもプロトタイプに乗せたい場合
var Animal = function(name) { this.init.apply(this, arguments); }; Animal.prototype.init = function (name) { this.name = name; };
初期化メソッドinit()を作って、コンストラクタではそれをapplyで呼ぶだけにする。
インスタンスを生成・メソッドを利用
var a = new Animal('taro'); a.getName();
継承
親クラス作成
var Animal = function(name) { this.name = name + '(Animal)'; }; Animal.prototype = { getName: function() { console.log('NAME: ' + this.name); } };
子クラス作成
var Human = function(name, age) { this.name = name + '(Human)'; this.age = age + '(Human)'; };
親クラスを継承
Human.prototype = new Animal;
なお、↑のままではHumanクラスのprototypeのconstructorプロパティはAnimalなので、これをHumanにする場合は↓のようにする。
Human.prototype = new Animal; Human.prototype.constructor = Human;
子クラスにメソッドを定義
Human.prototype.getAge = function () { console.log('AGE: ' + this.age); }
子クラスのインスタンスを作成・メソッドを利用
var h = new Human('jiro', 15); h.getName(); h.getAge();
子クラスで親クラスのコンストラクタメソッドを利用
var Human = function(name, age) { Animal.call(this, name); this.age = age + '(Human)'; };
var h = new Human('jiro', 15); h.getName();
親クラスであるAnimalを明示して、call()を使う。
プロトタイプ
プロトタイプチェイン
メソッドの検索は次の順で行われる。
- h.say()
- Human.prototype.say()
- Animal.prototype.say()
- Object.prototype.say()
親クラスを辿って行き、最終的にObject.prototypeで見つからなければ、終了する。
プロトタイプ継承の注意点
継承のために、
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のクラス(オブジェクト)の問題点
- 親クラスのコンストラクタ(メソッド)を呼び出すのが難しい。
- 多重継承が難しい。 これらを解決するには、何らかのライブラリを使うのが妥当。
参考
- 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/