読者です 読者をやめる 読者になる 読者になる

Javascriptでクラスっぽい動きを実現する

javascriptでクラスのような動きが実現を実現したいと思う。

通常javascriptではオブジェクトを生成するためのコンストラクタ
関数を呼び出すことでオブジェクトを生成する。クラスからのオブジェクト
生成はjavascript自体の機能としては持っていない。

function User(cards) {
   this.cards = cards;
   this.point = 0;
   this.take = function(card) {
     this.cards.push(card);
   };
};
var user1 = new user(new Array(“1”, “2”, “3”));

javascriptでは通常上記のようなコンストラクタ関数を呼び出してオブジェクトの生成を
行う。javaなどで開発を行ってきた人にとってはクラスを拡張することで開発を効率化
してきたと思うが、javascriptではクラスの概念がないので不便である。

その場合コンストラクタを拡張する方法などがある。
例えば以下のようなものである。

function User2() {
   function UserConstrucor() { 
      this.win = 0;
   };
   UserConstrucor.prototype = new User(new Array("3", "4", "5"));
   return new UserConstrucor();
};
var user2 = new User2();

上記のUserConstructorはUserオブジェクトを拡張するためのコンストラクタ関数である。
UserConstructorのプロトタイプにUserコンストラクタの生成オブジェクトを突っ込んでいる。
コンストラクタ関数によって生成されたuser2を確認したらわかると思うが、user2のプロパティに
はUserコンストラクタの精製物が含まれている。
これはjavascriptのプロトタイプチェーン機能によるものだ。prototyepプロパティに含まれるものは
自分自身のプロパティとして扱うことができる。

これでコンストラクタ関数の拡張はできる。
いちいちコンストラクター関数のprotptypeプロパティに値を突っ込むのが面倒であったり
すると思うが、以下の”JavaScript Ninjaの極意 ライブラリ開発のための知識とコーディング
”で紹介された方法を使うとよりクラス
に近い動きを実現できる。

(function() {
  var initializing = false,
      superPattern =  // Determine if functions can be serialized
        /xyz/.test(function() { xyz; }) ? /\b_super\b/ : /.*/;       //#1

  // Creates a new Class that inherits from this class
  Object.subClass = function(properties) {                           //#2
    var _super = this.prototype;

    // Instantiate a base class (but only create the instance,
    // don't run the init constructor)
    initializing = true;                                              //#3
    var proto = new this();                                           //#3
    initializing = false;                                             //#3

    // Copy the properties over onto the new prototype
    for (var name in properties) {                                    //#4
      // Check if we're overwriting an existing function
      proto[name] = typeof properties[name] == "function" &&
                    typeof _super[name] == "function" &&
                    superPattern.test(properties[name]) ?
          (function(name, fn) {                                        //#5
            return function() {
              var tmp = this._super;

              // Add a new ._super() method that is the same method
              // but on the super-class
              this._super = _super[name];

              // The method only need to be bound temporarily, so we
              // remove it when we're done executing
              var ret = fn.apply(this, arguments);
              this._super = tmp;

              return ret;
            };
          })(name, properties[name]) :
          properties[name];
    }

    // The dummy class constructor
    function Class() {                                                   //#6
      // All construction is actually done in the init method
      if (!initializing && this.init)
        this.init.apply(this, arguments);
    }

    // Populate our constructed prototype object
    Class.prototype = proto;                                             //#7

    // Enforce the constructor to be what we expect
    Class.constructor = Class;                                           //#8

    // And make this class extendable
    Class.subClass = arguments.callee;                                   //#9

    return Class;
  };
})();

上記方法を使うと、オブジェクトの生成が以下のように行える。

var User = Object.subClass({
  cards:’’,
  point:0,
  init: function(cards){
    this.cards = cards;
  },
  take: function(card){
    this.cards.push(card);
  }
});

var User2 = User.subClass({
  win:0,
  init: function(){
    this._super(new Array(“3”, “4”, “5”));
  }
});
var user2 = new User2();

こちらの方がよりクラスっぽくなった。