Internet Explorer 8 のネイティブ JSON

更新日: 2008 年 9 月 10 日


本記事は、Internet Explorer 開発チーム ブログ (英語) の翻訳記事です。本記事に含まれる情報は、Internet Explorer 開発チームブログ (英語) が作成された時点の内容であり、製品の仕様や動作内容を保証するものではありません。本記事に含まれる情報の利用については、使用条件をご参照ください。また、本記事掲載時点で、Internet Explorer 開発チーム ブログ (英語) の内容が変更されている場合があります。最新情報については、Internet Explorer 開発チームブログ (英語) をご参照ください。

翻訳元 : Internet Explorer 8 のネイティブ JSON (英語)



この投稿のタイトルから想像がついたかもしれませんが、Internet Explorer 8 は Beta 2 でネイティブの JSON 構文解析機能とサニタイズ機能を提供します。この新しい 新しいネイティブ JSON 機能により Internet Explorer 8 は AJAX アプリケーションを高速に、かつ安全に実行できるようになります。

JSON とは?

筋金入りの AJAX 開発者ではない方に、背景についての情報を少しだけ提供することをお許しください。JSON (JavaScript Object Notation) は単純で読解可能なデータ交換フォーマットで、 AJAX アプリケーションがサーバーと Web アプリケーション間でデータを送信する際によく利用されます。

例えば連絡先を確認するため、お気に入りの Web メール クライアントからあて先を選択した場合を想像してください。サーバーはこのようなデータ ストリームで ブラウザーで実行されている Web アプリケーションにデータを送信することができます。

     {

          "firstName": "cyra",

           "lastName": "richardson",

           "address": {

               "streetAddress": "1 Microsoft way",

                "city": "Redmond",

                 "state" : "WA",

                "postalCode": 98052

          },

          "phoneNumbers": [

               "425-777-7777", 

                "206-777-7777"

           ]

     }

幸いにも、このフォーマットは JavaScript と構文的な互換性があります。多くのアプリケーションが、現在ではデータ ペイロードを JavaScript オブジェクトに変換する際に JavaScript の eval() を使用しています。 eval() を使う方法は危険性があるアプローチです。eval() は文字列を一般的な JScript の表現として解釈し、実行します。もしeval() に渡される文字列に変更が加えられていた場合、それには予期しないデータや、他の誰かのコードが含まれているかもしれず、これらが Web アプリケーションに挿入されるかもしれません。

JavaScript で記述され、信頼できない JSON ペイロードをより安全に解析するために設計されたライブラリーがあります。いくつかのライブラリーは、 JScript で記述されたパーサーを使用して、データ ペイロードに対して、厳格な検証を行います (http://www.json.org/json_parser.js (英語)) 。 json2.js (英語) のような幾つかのライブラリーは正規表現を用いて入力された文字列の安全性チェックを実行し、そのあとで高速なeval() を利用した解析を行います。理想的な解決策は、高速でどこでも利用できる、コード インジェクションからアプリケーションを保護するネイティブな実装です。

Internet Explorer 8 JScript のネイティブ JSON

現在の Internet Explorer 8 に搭載されている JScript エンジンは、ES3.1 Proposal Working Draft (英語) の JSON のサポートと互換性を維持しつつ、シリアライズ (直列化) 、デシリアライズ、と サニタイズの速度を大幅に改良し、信頼できないペイロード解析の全体的な安全性を改良した完全にネイティブな JSON を実装しています。

API

新しいビルトイン オブジェクトである JSON を定義しました。オブジェクトは変更や上書き (オーバーライド) が可能です。それは math やその他の固有なグローバル オブジェクトのように見えます。また JSON オブジェクトに加えて、Date、Number、String、boolean オブジェクトのプロトタイプに toJSON() という特別な関数を追加しました。JSON オブジェクト自体は parse()stringify() という二つの関数を持っています。

例:

var jsObjString = "{\"memberNull\" : null, \"memberNum\" : 3, \"memberStr\" : \"StringJSON\", \"memberBool\" : true , \"memberObj\" : { \"mnum\" : 1, \"mbool\" : false}, \"memberX\" : {}, \"memberArray\" : [33, \"StringTst\",null,{}]";

var jsObjStringParsed = JSON.parse(jsObjString);

var jsObjStringBack = JSON.stringify(jsObjStringParsed);

parse() メソッドで生成され、stringify() メソッドでシリアライズできるオブジェクトは、以下と等価です。

var jsObjStringParsed =

{

    "memberNull" : null,

    "memberNum" : 3,

    "memberStr" : "StringJSON",

    "memberBool" : true ,

    "memberObj" :

     {

                "mnum" : 1,

                "mbool" : false

    },

    "memberX" : {},

     "memberArray" : 

     [

                 33,

                "StringTst",

                null,

                 {}

     ]

};

JSON.parse(source, reviver)

JSON.parse(source, reviver) メソッドはデシリアライズを行います。これは JSON フォーマットの文字列 (source 引数によって与えられます) を処理し、JScript オブジェクトまたは配列を生成します。

オプションの revive argument は解析後の動作を変更するためのユーザー定義の機能です。生成されるオブジェクトや配列は再帰的に走査され、reviver の内容はすべてのメンバーに適用されます。それぞれのメンバーの値は reviver が返す値によって置き換えられます。reviver が null を返すと、そのオブジェクトのメンバーは削除されます。reviver の呼び出しと走査は処理の実行後に行われます。そうです、どのオブジェクトも、そのすべてのメンバーが「更新された」後に「更新される」のです。

reviver はおもに ISO 的な文字列を認識して Date オブジェクトに変換するのに使われます。現時点では、JSON フォーマット (英語) に Date リテラルについての JScript の標準がないため、Date オブジェクトに関しては可逆的ではありません。ES3.1 draft (英語) にはこの問題を reviver を使って解決するための例が含まれています。

JSON.stringify(value, replacer, space)

これはシリアル化を実行するメソッドです。value 引数で指定されたオブジェクトまたは配列を処理し JSON フォーマットの文字列を生成します。value として与えられたオブジェクトまたは配列は再帰的に検査され、JSON フォーマット (英語) に沿ってシリアル化されます。value に 'toJSON()' メソッドが含まれる場合、これは最初のフィルターとして機能します。オリジナルの valuevalue.toJSON(key) で置き換えられ、その結果の値がシリアル化されます。ここで引数 key は文字列であり、(key : value) のようなオブジェクトのメンバーをシリアル化する場合の、メンバー名 key です。ルート オブジェクトでは key は空の文字列です。

Date.prototype.toJSON() はエスケープすべきキャラクターを含まない安全な文字列を生成します。stringify() は元の文字列を変更せずそのまま返すため、これが事実上のシリアル化機能として動作します。Date オブジェクトは toJSON() メソッドを経由することでシリアル化されます。

Number.prototype.toJSON()String.prototype.toJSON()Boolean.prototype.toJSON() は ValueOf() を返します。これらは "var num = new Number(3.14);" のようなオブジェクトを適正にシリアル化することを意図しています。

オプションの引数 replacer はフィルターとして動作し、再帰的に適用されます。この引数には関数または配列が使用できます。replacer が関数の場合、replacer(key,value) はオブジェクト メンバーのである key:value のそれぞれに対して作用します。ルート オブジェクトに対しては replacer("",value) を呼び出します。replacer が配列の場合、その配列は文字列の配列でなければなりません。配列の要素はシリアル化の対象となるよう選択されたメンバー名です。シリアル化の順序は配列中の名前の順になります。配列のreplacer は配列をシリアル化する際は無視されます。

オプションの引数 space は出力するテキストのフォーマットを指定します。この引数が省略されると、テキストは余分な空白を含まないよう圧縮されます。数字が指定されると、テキストは階層ごとに指定された数の空白文字でインデントされます。'\t' や ' ' のような文字列が指定されると、階層ごとのインデントに指定した文字が使用されます。

既存のページにどのような影響を及ぼすか

JSON に関する ESS 3.1 プロポーザルは、広く利用されている json2.js を利用したファーム ファクターです。我々も JSON という名前は継承します。グローバルな JSON オブジェクトは上書き (オーバーライド) 可能です。そしてもう未定義のオブジェクトではありません。開発言語に新しいキーワードを導入した場合と同じく、名前を継承することで既存のコードに対して影響が及ぶかも知れません。json2.js を使用して作成されたページが影響を受ける可能性はほとんどありません。極めて少ない例外を除いて、すべてのページは速くなるだけでこれまで通りに動作し続けます。

JSON オブジェクトのプライベートな実装が定義されているページ、特に "if(!this.JSON) { JSON=…}". といったパターンで JSON オブジェクトの実装が定義されている時には、影響を受ける可能性があります。この種の問題に対する対処方法として、主にふたつの選択肢があります。

1. 既存のコードをネイティブ JSON サポートを使用するよう移行する

いずれかのバージョンの json2.js を基にしてプライベートな JSON 実装をしている場合、とても簡単に移行できるはずです。

2. ネイティブ JSON サポートをオプト アウトし、既存の JSON オブジェクトを引き続き利用する

これは JSON の名前を変更、もしくはオーバーライドすることで実行できます。名前の変更は、すべてのコード上で用いられている "JSON" という名前を "MyJSON" というように異なる名前に変更することを意味します。オーバーライドの意味は、すべてのプライベートな JSON の定義を、既定の JSON 定義 で置き換えることを意味します。ほとんどの場合、"if(!this.JSON)" を取り除くことで、うまくいくはずです。

ES3.1 の標準化の努力を考えれば、"JSON" の名前を使用することは、定義に関するインターフェイスの相互運用性を確保したという我々の希望と合致します。

ネイティブ JSON についてさらにお伝えすることがあります。パーサーは eval() を基にしているのではなく、独自に実装しています。 JSON サポート (英語) で提供されるリファレンス パーサーと同等のものです。それは http://www.json.org/ と同じくらい安全で、かなり高速です。もし eval() や独自の JSON ライブラリーを使用しているのであれば、パフォーマンスと安全性を向上させるために Internet Explorer 8 に搭載されているネイティブな実装をチェックすることを検討してください。

Corneliu Barsan
Senior Developer
JScript team

 

ページのトップへページのトップへ