値として関数を持った「JSONもどき」、使いたい時ってないですか?
皆さん、ご存知の通り、
var json_modoki =
{
foo:100,
boo:"sample text",
hoge: {
muda: "よろしく"
},
func: function() { console.log("hello world"+this.hoge.muda); },
func2: function() { console.log("hello japan"+this.hoge.muda); }
}
のような、値として関数を持っているようなものはJSONの仕様上、許されていません。
でも、こういう関数を持った「JSONもどき」って、たまに便利なときがありますよね。
ただ、問題なのがこういう「JSONもどき」ではJSON.stringifyによる文字列化や、
文字列化したものをJSON.parseで「JSONもどき」へ戻すことができないということ。
困りましたねー。
ということで、解決策を作ってみました。いや、私が作ったというか、白状しますと、2chで質問したらスーパーハカーな方が基本的なアイデアを教えてくれました。ありがとうございますw
基本方針
基本方針は、「JSONもどき内で値が関数のものは、文字列に変換する」です。
そして、「JSON.parseするときに、独自のパーサーを渡して、パーサー内で関数文字列をevalして関数に戻す」というものです。
詳細はコードを御覧ください。
function convertFunctionsToStringsInJSON(json_with_function) {
var json = json_with_function;
for (key in json) {
if(typeof(json[key]) === "function") {
json[key] = json[key].toString();
}
}
return json;
}
var json =
{
foo:100,
boo:"sample text",
hoge: {
muda: "よろしく"
},
func: function() { console.log("hello world"+this.hoge.muda); },
func2: function() { console.log("hello japan"+this.hoge.muda); }
}
convertFunctionsToStringsInJSON(json);
console.log("stringified:"+JSON.stringify(json));
var jsonText = JSON.stringify(json);
var parser = function(k,v){return v.toString().indexOf('function') === 0 ? eval('('+v+')') : v};
var json2 = JSON.parse(jsonText, parser);
json2.func();
json2.func2();
上記のコードは、jsdo.itでも公開しています。
追記:もっと簡単なやり方
追記:関数の文字列化については、もっと簡単な方法があります。
Function.prototype.toJSON = Function.prototype.toString;
とすると、JSON.stringifyの処理での関数の評価時に自動的にtoString()が発動します。
Function.prototype.toJSON = Function.prototype.toString;
var json =
{
foo:100,
boo:"sample text",
hoge: {
muda: "よろしく"
},
func: function() { console.log("hello world"+this.hoge.muda); },
func2: function() { console.log("hello japan"+this.hoge.muda); }
}
console.log("stringified:"+JSON.stringify(json));
var jsonText = JSON.stringify(json);
var parser = function(k,v){return v.toString().indexOf('function') === 0 ? eval('('+v+')') : v};
var json2 = JSON.parse(jsonText, parser);
json2.func();
json2.func2();
こちらもjsdo.itで公開しました。
最後に
いかがでしょうか。もちろん、こんな「JSONもどき」他のサービスとやりとりしたりなどすることはないと思いますが、自アプリ・自サービス内で内部的に使うのはアリだと思います。
そんなに多くないと思いますが、「このTips使えそう」と思ってくれた方がいらっしゃれば幸いです。