サーバーサイドJSのための、JSONで復元できるモデルクラス *追記あり*

ほとんど自分のためのメモ。
サーバサイドJSを使っているとクライアントにwebsocket経由で渡したりmongodbやnstoreで永続化する際にピュアなJSONとしてデータを宣言しなおす必要があって面倒。

じゃあModelクラス自身が読み込み/書き出しできると嬉しいのでは。
coffee-scriptで書いてみた。

class Model 
  _iparam_ : {}

  constructor : (data={})->
    for k,v of @_iparam_
      @[k] = data[k] or @_iparam_[k] 

  toJson : (cls)->
    return @toJson(@) if cls is undefined 
    return cls unless cls instanceof Object

    json = {}
    for k,v of cls
      if typeof v is 'function' or k[0] is '_'
      else if typeof v in ['string','number','boolean']
        json[k] = v
      else if v instanceof Array 
        json[k] = (@toJson(v[i]) for i in [0...v.length])
      else if v instanceof Object
        json[k] = @toJson(v)
    return json

ルール

継承して_iparam_というプロトタイプに初期化用パラメータを詰め込む(実際のモデルスケルトン)
モデルの引数にインスタンス(JSだからオブジェクトだけど)を作ると元のパラメータが復元される
アンダースコア(_)をプレフィックスに持つ変数は無視
Model#toJsonでJSONに書き出し

サンプル

class A extends Model
  _iparam_ :
    x : 1
    y : 2
    _y : 5  #無視
    z : [1,3,5]

  constructor : (data={})->
    super data

  func : ->
    # 関数定義してもjson化する際には無視する
    @x+@y

使う

> a = new A
> alt = new A { x: 330 }
> console.log alt
{ x: 330, y: 2, _y: 5, z: [ 1, 3, 5 ] }
> console.log alt.toJson()
{ x: 330, y: 2, z: [ 1, 3, 5 ] }

toJsonしたJSONを引数にモデルクラスを作成すると元のパラメータが復元される
そのままコントローラをmixinしたりして使うと何かと楽

追記

ちょっと改良
undefinedのみスルーするようにしないとfalseや0のとき失敗する
いらないパラメータは_をフラグにするのではなく_ignore_で宣言する

class JsonLoader
  _init_ : {}
  _ignore_: {}

  constructor : (params={})->
    for k,v of @_init_
      if params[k] is undefined
        @[k] = @_init_[k] 
      else 
        @[k] = params[k]

  toJson : (cls)->
    return @toJson(@) if cls is undefined 
    return cls unless cls instanceof Object

    json = {}
    for k,v of cls
      if typeof v is 'function' or @_ignore_[k]?
      else if typeof v in ['string','number','boolean']
        json[k] = v
      else if v instanceof Array 
        json[k] = (@toJson(v[i]) for i in [0...v.length])
      else if v instanceof Object
        json[k] = @toJson(v)
    return json

サンプル

class MyClass extends JsonLoader
  _init_ : 
    n : 1
    str : 'test'
    bool : false
  _ignore_: 
    ng : 0

  constructor:(data)->
    super data
    @ng = 0
    
myclass = new MyClass
myclass.toJson() #ngを含まない

実際には別のクラスを参照したりして再ロード時に邪魔になるパラメータが多いということにきづいた。