JSONの書き方について考えてみた・2

昨日の続き。
はてブ注目のエントリーに入ったのを見て、『考えてみた』ではなく『考察』と、かっこいいタイトルにしておけばよかったと思いつつも、このままでいきます。

冒頭部での読み込み完了コールバックの仕込み

追加対応型だと、最後に読み込み完了のコールバックを書くことができません。
「最後にコールバックをかけないのなら、冒頭部にコールバックを書けばいいのに。」とどこかの王妃が言ったかどうかは知りませんが、

if (typeof(Hoge) == 'undefined') Hoge = {};
Hoge.data = [];
if (typeof(Hoge.onload) == 'function') {
  Hoge.onload(Hoge.data);
}
Hoge.data.push('text');

このように書いても駄目なのは明らかです。空の配列が渡されます。
次のように書くとうまくいきます。

/* 略 */
if (typeof(Hoge.onload) == 'function') {
  setTimeout(function(){Hoge.onload(Hoge.data);}, 0);
}
/* 略 */

0ミリ秒後に実行ということで、先ほどのと変わらないようにも思えますが、setTimeoutのカウントが一連の処理が終わってから始まるようで、うまいことに読み込みが完了してから呼び出されます。(windowsIEFirefoxで確認)

先頭評価値の指定

JSONのデータをオブジェクトに格納する書き方をした場合、最初にそのオブジェクトを用意する必要があります。

if (typeof(Hoge) == 'undefined') Hoge = {};

このため、次のやり方で取得しようとするとエラーになります。

eval('var data = ' + jsonText);

そこで、無理やり解決してみます。

(function() {
if (typeof(Hoge) == 'undefined') Hoge = {};
Hoge.data = [];
return Hoge.data;
})();
Hoge.data.push('text');

冒頭の処理を無名関数にすることで、最初の評価値を任意の値に変えてしまいます。

追加対応型をeval戻り値での取得に対応させる

追加対応型を利用すると、最後の評価値は最後に追加したデータになります。

if (typeof(Hoge) == 'undefined') Hoge = {};
Hoge.data = [];
Hoge.data.push('text');
Hoge.data.push('hoge');
Hoge.data.push('fuga');

これだと、

var data = eval(jsonText);

とするとdataは'fuga'になります。
どうしてもevalの引数で取得したいという場合は、こうすると何とかなります。

if (typeof(Hoge) == 'undefined') Hoge = {};
Hoge.data = [];
Hoge.data.push('text');
Hoge.data.push('hoge');
Hoge.data.push('fuga');
Hoge.data

見てわかるように、最後にHoge.dataを追加しただけです。
ここにデータを追加する場合は、

.push('foo');
Hoge.data

を追加しましょう。

まとめ

ひとつにまとめてみた。

(function() {
  if (typeof(Hoge) == 'undefined') Hoge = {};
  Hoge.data = [];
  return Hoge.data;
})();
if (typeof(Hoge.onload) == 'function') {
  setTimeout(function(){ Hoge.onload(Hoge.data); }, 0);
}
Hoge.data.push('text');
Hoge.data.push('hoge');
Hoge.data.push('fuga');
Hoge.data

これで、XMLHTTPRequest+evalでの2通りの取得可能、script要素を使った別ドメインからの利用も読み込み完了コールバックつきで可能、データの追加は追加書き込みで可能という豪華なJSONができました。
正直なところ、先頭評価値の指定はなくていい気もしますが。

あとがき

これまでJSONといい続けたのですが
どう見てもJavaScriptコードです。
本当にありがとうございました

JSONの仕様から逸脱したかたちになりましたが、JavaScriptでの利用と割り切ればこういった形もアリではないでしょうか。