Hatena::ブログ(Diary)

sshi.Continual このページをアンテナに追加 RSSフィード

プロフィール

sshi

SFと映画と小説とRuby信者(最近はhaskellびいき)です。

 | 

2006-09-04 Mon

JavaScriptJSONをeval JavaScriptでJSONをevalを含むブックマーク

JSON文字列をevalして値を取りたいときに挙動が妙ではまった、という話を聞いたので、Firefox1.5上のFireBugのコンソールで何パターンか試してみた。

{"key":"value"}というJSONデータが文字列で渡ってきて、それをevalしてJavaScriptの値として使いたい、という想定。

間違ったJSON文字列をevalした場合

>>> jsonstr = "{key:\"value\"}"
"{key:"value"}"
>>> var obj = eval(jsonstr)
>>> obj
"value"
>>> typeof(obj)
"string"

JSONオブジェクトでは、ラベルも""でくくって文字列にしないといけないのだが、まずはそれを忘れた場合を試してみた。結果として返ってくるのは、なんとJSONハッシュの要素にしたつもりの文字列のみ。

正しいJSON文字列をevalした場合

>>> jsonstr = "{\"key\":\"value\"}"
"{"key":"value"}"
>>> var obj = eval(jsonstr)
invalid label
{"key":"value"}

今度は、keyのほうもちゃんと""でくくってみた。ところが、evalした途端に invalid labelなる謎のエラーがでる。ぱっと見何が起ってるかさっぱりわからない。

代入文をeval

しょうがないので、"obj ="も文字列に含めてevalしてみる

>>> jsonstr = "{\"key\":\"value\"}"
"{"key":"value"}"
>>> eval("obj="+jsonstr)
[object Object]
>>> obj
[object Object]
>>> obj.key
"value"

これはちゃんとObjectが返ってきてるし、ハッシュとしてアクセスもできる。成功。

JSON文字列を"()"でくくる

JSON文字列を()でくくってevalする。これはprototype.jsで使われている手法らしい。

>>> jsonstr = "{\"key\":\"value\"}"
"{"key":"value"}"
>>> obj = eval("("+jsonstr+")")
[object Object]
>>> obj.key
"value"

これも成功。何故か、()でくくるだけで謎のinvalid labelエラーはでなくなる。

謎とき

結論としては、JSON文字列をevalするときは、代入文にするか全体を()でくくってevalしろ、ということになる。では何故最初の二つのケースでは失敗しているのか?特に、"invalid label"ってなにか?

JavaScriptの文法定義(http://www.mozilla-japan.org/js/language/grammar14.html)を見てみるとこの謎が解ける。JavaScript1.5にはラベル文(LabeledStatement)というものがあって、さらにラベル文のラベル部分は"Identifier :"と定義されているので、文字列はここには書けない。

構文やevalの仕様を全部ちゃんと読んでないので、ここから先は推測だけど、最初の二つのケースでは、evalする対象の文字列がJSON(Object Literal)として解釈されずに、Block("{}"でくくった文の集合)の中のラベル文(LabeledStatement)として解釈されているのだろう。

つまり、一番最初のケースでは、{key:...}がラベル文と解釈されて、かつ、key:はラベルとして適正なのでエラーもでない。ラベルと見なされたkey:の後に続く"value"が、このラベル文の値になるので、evalの結果として"value"という文字列だけが返ってくる。二番目のケースでは、{"key":..}がラベル文と解釈されて、かつ"key"がラベルとしては不適正なのでエラーがでる。これが"invalid label"の正体。

三番目では代入文に、四番目では"()"をつけたことによって、{"key":..}がラベル文ではなくJSON(Object Literal)として解釈され、期待通りの動作になる。

まー、prototype.jsみならって"()"つけとけってことかな。ラベル文の使い方については次に続く。

mal_bluemal_blue 2006/09/04 15:27 Fx1.5 は JS1.6 っす。

リンク元
 | 

あわせて読みたい
sshi.Continual 942332 なかのひと RSS feed meter for http://d.hatena.ne.jp/sshi/
Connection: close