NeDBのserializeメソッドにおけるちょっとしたHack

公開:2016-06-07 22:00
更新:2020-02-15 04:37
カテゴリ:nedb

ちょっとしたHackを発見したので書いておく。というかコメントにそれらしきことが書いてあったので。。

下記のコードはNeDBのmodel.js中にあるserializeメソッドのコードである。ちょっとNeDBがどのようにデータをシリアライズしているのか興味があったので覗いてみたのである。

function serialize (obj) {
  var res;

  res = JSON.stringify(obj, function (k, v) {
    checkKey(k, v);

    if (v === undefined) { return undefined; }
    if (v === null) { return null; }

    // Hackish way of checking if object is Date (this way it works between execution contexts in node-webkit).
    // We can't use value directly because for dates it is already string in this function (date.toJSON was already called), so we use this
    if (typeof this[k].getTime === 'function') { return { $$date: this[k].getTime() }; }

    return v;
  });

  return res;
}

シリアライズについてはJSON.stringifyを使っている。Dateは文字列にシリアライズされてしまうので、replacer{$$date: (Dateのシリアル値)}という形のオブジェクトに変換している。これは同じくmodel.js中のdesrializeメソッドの中で、JSON.parsereviverで逆にDateに戻している。なるほど、replacer/reviverはこういう用途で使用するのだな。

function deserialize (rawData) {
  return JSON.parse(rawData, function (k, v) {
    if (k === '$$date') { return new Date(v); }
    if (typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean' || v === null) { return v; }
    if (v && v.$$date) { return v.$$date; }

    return v;
  });
}

でまあちょっとしたHackというのは以下のコードなんだけどね。

    // Hackish way of checking if object is Date (this way it works between execution contexts in node-webkit).
    // We can't use value directly because for dates it is already string in this function (date.toJSON was already called), so we use this
    if (typeof this[k].getTime === 'function') { return { $$date: this[k].getTime() }; }

なんかnw.js中の実行コンテキストでも動作する方法だと書いてある。さらにはreplacer(k,v)vはシリアライズされた値なので、この場合Dateだから文字列に置換されてしまっているため、Date型であるかどうかは容易に判断することができない。なんで容易に判断できないのかというと、生成される文字列がブラウザや環境で異なるからである(古い情報。今ってどうなのかね?)。なのでthis[k]でシリアル化前のオブジェクトを取り出して、getTimeメソッドの有無でDate型かどうかを判断しているのであった。

まあちょっとしたHackだね。