ちょっとした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.parse
のreviver
で逆に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だね。