クラスの作り方 - 関数オブジェクトを使って

クラスを作成

空のコンストラクタ

 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/

トップ   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS