それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

JSON.stringify で関数(funciton) も文字列化、JSON.parseでdeserialize する。

JavaScriptJSONはprimitiveな変数だけしか扱えなかった。

JSONというのは、本当にお前さんらはね。サムライになれないんだよ。

JSON

var obj = {"a": "takuya", "say":function(){ console.log(`My name is ${this.a}.`) } }
obj.say()
//=>My name is takuya.

このオブジェクトをJSONでString化すると

stringify すると関数消える。

JSONがサムライになれない理由がコレ。

JSON.stringify(obj)
"{"a":"takuya"}" // function 消される。

これは仕方ないんだよ。 function が定義されるタイミングで、変数のスコープもあるし。でも初回ロードとか別にスコープを気にしない時になんとかならないか調べた。

JSON で関数も保存したい!

なんとかならないか調べた。

JSON.stringify/parseの第二引数を使う。

JSON.stringify には第二引数を指定できて、オブジェクトの値をどのようにして、文字列化するか指定できる。

JSON.stringify(value[, replacer[, space]])

ここでReplacerを使えばなんとかなりそう。

文字列化関数を指定してみる。
function replacer (k,v){ 
 e if(typeof v === "function"){ return v.toString() }; 
  return v ;
}
str= JSON.stringify(obj, replacer)
//=> "{"a":"takuya","say":"function (){ console.log(`My name is ${this.a}.`) }"}"

おお?文字列化出来る。 可能性が出てきた。

JSON.parse指定してみると
JSON.parse(str)
//=>Object {a: "takuya", say: "function (){ console.log(`My name is ${this.a}.`) }"}

文字列化したから、関数も文字列になってしまう。そりゃそうだ。

JSON.parse を調べてみると

JSON.parse(text[, reviver])

replacer の逆のreciever があることが分かった。試してみよう。

JSON.parse の第二引数を使ってみる

第二引数で、文字列化した関数 を元に戻せないか試してみよう。

a = '{"a":"takuya","say":"function(){ console.log(this.a)}"}'
function reciever (k,v ) {  
  
  if ( typeof v === "string" && v.match(/^function/) ){
    return Function.call(this, "return "+ v  )();
  }
  return v 
}

var a = JSON.parse( a ,reciever)


a.say() //=>takuya

おお!?戻った戻ったよ! メソッドを入れたObjectをシリアライズして元に戻せるじゃん。

出来るじゃん!

これ、メッチャ便利じゃね?

ネストしたJSON.stringify() も大丈夫!

ネストしたらどうなるのか、試してみた。

a = '{"name":"takuya","pets": [{ "name": "taro", "say": "function(){ console.log(this.name)}" }] } '
function reciever (k,v ) {  
  
  if ( typeof v === "string" && v.match(/^function/) ){
    return Function.call(this, "return "+ v  )();
  }
  return v 
}

var a = JSON.parse( a ,reciever)


a.pets[0].say(); //=> taro

出来るじゃん。

まとめ

  • JSON.parseで関数も渡せる
  • JSON .stringify で関数が渡せる
  • JSON.stringify ( obj ,replacer) でfunction もString化出来る
  • メソッドを持ったObjectをJSONシリアライズ出来る
  • JSONで作ったオブジェクトにメソッドをもたせたまま、転送できる
  • JSONはデータ交換だけじゃなく、使い方では「インスタンス」を渡せそう。
  • JSONで関数もデシリアライズできるから、状態保存と状態の復元が手軽にできる。

ただし、parse 時の変数のスコープに差異があり、変数のスコープまで意識して完全に同じになる保証はできない。ただthis くらいはなんとかなるとわかった。工夫次第で同じスコープは再現できそう。

JSONの痒い所に手が届かない感じで、世界一のサムライになれない感じがあった。 世界が広がる。Javascriptは戦うサムライになれる。

参考資料

JSON.stringify() - JavaScript | MDN

eval() - JavaScript | MDN

Function.prototype.call() - JavaScript | MDN

JS 形式の設定ファイルを読み込むときは eval の代わりに new Function を使う - たそがれ日記

関連資料

Chrome Extension のcontent scriptでの変数隔離に対応する。 - それマグで!