Hatena::ブログ(Diary)

IT-Walker on hatena このページをアンテナに追加 RSSフィード

2009-09-07 JSON.stringify/parseは困ったもんだ。

JSON.stringify/parseは困ったもんだ。

JavaScriptオブジェクトJSONに変換する際、必ずと言っていいほど使われるのがjson2.js

ECMAScript5(JavaScript2)では、json2.jsの実装をほぼ忠実に仕様として再現しており、Firefox3.5やSafari4ではネイティブの実装が利用できます。


例えば、JSオブジェクトJSON文字列にしたい場合は、JSON.stringify(value, replacer, space)を利用できます。

valueはJSオブジェクト

replacerは省略可能で、function(key, value)と言うシグネチャ関数オブジェクトを渡します。JS文字列の変換ルーチンを独自に提供できます。

spaceは、結果の文字列を人間が読みやすくするための、インデントの数を指定します。


その逆に、JSON文字列JSオブジェクトに復元したい場合は、JSON.parse(text, reviver)を使用します。

textはJSON文字列

reviverは省略可能で、function(key, value)と言うシグネチャ関数オブジェクトを渡します。文字列JSの変換ルーチンを独自に提供できます。


てな感じで非常に便利なJSON.stringify/parseですが、とにかく困るのが以下の二点。

JSON文字列からDateを復元できない

Date型をJSONに変換すると、ISO-8601形式の文字列になるんですが、その文字列をparseしても元に戻らない。

JSON.parse(JSON.stringify(new Date()));

2009-09-07T04:49:43Z // 上の実行結果は、ISO-8601形式のStringになる。Dateが戻ってきて欲しい・・・

そもそも、JSONの仕様にDate型が含まれていないのがツライところなんですが・・・

Date型をstringifyすると、ブラウザによって実行結果が異なる

上の説明で、「Date型をJSONに変換すると、ISO-8601形式の文字列になる」と書きましたが、ここにも問題が潜んでます。

ブラウザによって、シリアライズした結果の文字列が微妙に異なってしまうのです。

JSON.stringify(new Date())を各ブラウザで実行した結果は以下の通り。

Firefox・・・2009-09-07T04:49:43.400Z
Safari4・・・2009-09-07T04:49:43Z

一見して分かる通り、Safari4ではミリ秒の情報が抜け落ちてしまっています。

シリアライズするだけで情報が落ちてしまうのは非常に困ります。


ECMAScript 5th Editionの仕様書見ても、恐らくFirefoxの挙動の方が正しく思われたので、WebKitMLバグ報告しておきましたが・・・果たしてどうなることやら(僕の方が仕様を誤解している可能性も大)。


とりあえず現時点では、Date型を含むオブジェクトJSON化したい、と言うニーズは容易に満たされそうにありません。JSONにするまえに、Date.getTime()でミリ秒を表すNumberに変換しておくのが一番問題ない気がします。。(表現に必要なバイト数も少ないし、どの環境でも元の値を間違いなく復元できるし・・・人間には読めないけど)


stringify()/parse()に渡せるカスタマイズ用関数で、ソリューションを提案してる人も居るので一応紹介。

http://west-wind.com/weblog/posts/729630.aspx

ただ、全フィールドに対して正規表現でマッチを試みるので、パフォーマンスが心配すぐる。。

はてなユーザーのみコメントできます。はてなへログインもしくは新規登録をおこなってください。

リンク元