javascriptで簡単にクラス定義できるライブラリを作ってみました　第２弾


#はじめに

このライブラリはjavascriptでクラス定義がどうのこうのってハマってしまった人の指標になればと思います。

本当にこの話題はいろんなところであがっていますよね。でもどれもスッキリしないですよねぇ。

今回はjavascriptの癖のあるオブジェクト指向を、javaだとかのいままでの知識でなるべく楽したい人にオススメです。

 > javascriptにはクラスなんてないあるのはオブジェクトだけとか。なにもわざわざクラスを作らなくてもいいとか。こだわる人にはすすめません。

以前node.js用に作ってみた[クラス定義モジュール](http://qiita.com/cocottejs/items/cfcc673357d9d9cf61fc)をクライアントサイドでも使えるようにしてみました。  
とはいっても、グローバル汚染対策とnodeで使用していた`util.inherits`を定義し直しただけです。

[Github](https://github.com/yukik/cocotte-define)

以前投稿した[プロパティ](http://qiita.com/cocottejs/items/0c1756ac7e7ec8bae7cb)、[メソッド](http://qiita.com/cocottejs/items/f7cb629ad17de04bf2fc)、[継承](http://qiita.com/cocottejs/items/e75f751c7aa8a7361aab)、[Getter/Setter](http://qiita.com/cocottejs/items/35e0edef71d8c0fc3348)の落とし穴を簡単に回避するようになっています。

難しい事を考えずにクラス定義を効率よくするためにこれからもバージョンアップしていきたいですね。

以前の投稿から、メソッドのオーバーロード、継承、prototypeへの定義の機能を追加しました。

# こんなことできます

使用方法は[README.md](https://github.com/yukik/cocotte-define)にまとめてありますが、(自分で書いておきながら)読むのが面倒なので、簡単に紹介します

## 基本系

使用するファイルは[client.js](https://github.com/yukik/cocotte-define/blob/master/client.js)だけです。
とりあえず、ネームスペース`Cocotte`に定義関数`classDefine`が設定されています。
そこらへんは自分の好きなように変更しちゃってください。

```js
var Klass = function Klass() {
  this.def(Klass);
};
Cocotte.classDefine(Klass);

Klass.properties.プロパティ名 = 定義
Klass.setMethod(メソッド名, 定義);
```

なんか統一感ないなと思われるかもしれません、、、実は
プロパティを定義する方法は、他にも`Klass.setProperty(プロパティ名, 定義)`が存在しますが、推奨は`Klass.properties`で。
同じく、メソッドを定義する方法は他にも`Klass.methods.メソッド名 = 定義`が存在しますが、推奨は`Klass.setMethod`で。
一応理由があるんですが、面倒なので省略します。
> GitのREADME.mdにて確認ください

## プロパティの型を簡単に設定したい

```js
Klass.properties.name = {type: String};
```

違う型を設定すると例外が発生します

## プロパティを独自にいろいろ定義したい

```js
Klass.properties.birthday = function (pv) {
  return {
    // 入力値を先に変換したり
    exchange: {
      from: String,
      to: function (val) {
        return new Date(val);
      }
    },
    // 型指定したり
    type: Date,
    setter: function (val) {
      // 設定時にプライベート変数に格納したり
      pv.birthday = val;
    },
    getter: function () {
      // プライベート変数から取得したり
      return pv.birthday;
    }
  };
};
```

入力値によって、処理をかえたい時に便利です。
 > むしろjavaではgetter/setterの実装が遅れているので、こっちのほうが便利かも。

## メソッドの引数の型をチェックしたい

```js
Klass.setMethod('setHolidays', {
  params: [String, [Date]],
  method: function (name, holidays) {
    this.holidays[name] = holidays;
  }
});
```

配列の場合は要素の型も確認できるようになっています


## メソッドをオーバーロードさせたい

同じメソッド名で登録するとオーバーロードになります

```js
Klass.setMethod('setName', {
  params: [String],
  method: function (val) {
    this.name = val;
  }
});
Klass.setMethod('setName', {
  params: [Number],
  method: function (val) {
    this.setName('A' + val);
  }
});
```

# 継承を簡単に実現したい

```js
// 親クラス
var SuperKlass = function SuperKlass (prop1) {
  this.def(SuperKlass);
  this.prop1 = prop1;
};
Cocotte.classDefine(SuperKlass);
SuperKlass.properties.prop1 = {type: String};

// サブクラス
var Klass = function Klass (prop1, prop2) {
  this.def(Klass, prop1);
  this.prop2 = prop2;
};
Cocotte.classDefine(Klass, SuperKlass);
Klass.properties.prop2 = {type: String};

// インスタンス
var k = new Klass('foo', 'bar');
console.log(k.prop1); // 'foo'
```

# 普通のprototypeの定義とも同居できるよ

次のようにいつもの定義と`setMethod`で定義したメソッドは同居できます。

```js
Klass.prototype.getPrice = function () {
  return Math.floor(price * 1.08);
};
```

 > ただし、同名のときは後に定義したもので、上書きされます

# クラスの使い方も変わらないよ

```js
var instance = new Klass('foo', 123);
instance.name = 123; // 一番最初の例だとここで例外発生
instance.setName(123); // オーバーロードの例だとname='A123'
```

# 最後に

まだまだ実装できていない機能はたくさんありますけど、そこはやったりやらなかったり追々きめようかな。
> インターフェースとか、privateメソッドとか、オーバーライド禁止、抽象クラスとか

javascriptはそのままなんにも考えずに使うと本当に落とし穴がおおくて、無駄に時間を消費してしまいます。
すこしでもお役に立てれば幸いです。またライセンスはMITですので後はご自由に。