JavaScriptのJSON.parse()

JavaScriptのJSON.parse()を学びましょう。文字列からオブジェクトへの変換、reviver関数、エラーハンドリング、信頼できないJSON入力のセキュリティ上の考慮事項を解説します。

Conversion

詳細な説明

JSON.parse() は、JSON形式の文字列をネイティブのJavaScript値に変換するための組み込みメソッドです。JSON.stringify() の対になるもので、APIからJSONデータを受信する、localStorageから読み取る、JSONファイルを処理する際に使用されます。

メソッドシグネチャ:

JSON.parse(text, reviver?)
  • text: パースするJSON文字列(有効なJSONでなければならない)
  • reviver: パースされた値を変換するオプションの関数

基本的な使い方:

const data = JSON.parse('{"name":"Alice","age":30}');
console.log(data.name); // "Alice"
console.log(data.age);  // 30

reviverパラメータ:

reviver関数はパース中のすべてのkey-valueペアに対して呼び出され、値を変換できます。一般的な用途は、日付文字列をDateオブジェクトに戻すことです:

const data = JSON.parse(jsonString, (key, value) => {
  if (key === 'createdAt' || key === 'updatedAt') {
    return new Date(value);
  }
  return value;
});

reviverはパースされたツリーをリーフからルートへと走査するため、ネストされた値はその親よりも先に変換されます。

エラーハンドリング:

JSON.parse() は入力が有効なJSONでない場合に SyntaxError をスローします。常にtry/catchブロックで囲む必要があります:

try {
  const data = JSON.parse(userInput);
} catch (error) {
  console.error('Invalid JSON:', error.message);
}

エラーメッセージはJavaScriptエンジンによって異なりますが、通常はパースが失敗した位置を含みます。

セキュリティ上の考慮事項:

古いJavaScript環境では、開発者がJSONのパースに eval() を使用することがありましたが、eval() は任意のコードを実行するため非常に危険です。JSON.parse() はこの点で安全です。データのパースのみを行い、関数の実行や変数へのアクセスはできません。ただし、信頼できないJSONのパースは、パースされたオブジェクトを無差別に他のオブジェクトにマージする場合、プロトタイプ汚染攻撃のベクターとなり得ます。lodash.merge などのライブラリには、パースされたJSONの __proto__constructor のようなキーがオブジェクトプロトタイプを変更できる脆弱性がありました。

開発者がよくやるミス:

よくあるエラーは、すでにJavaScriptオブジェクトである値に対して JSON.parse() を呼び出すことで、JSON.parse() は文字列を期待するため失敗します。パース前に typeof value === 'string' を確認してください。もうひとつのミスはエラーケースを処理しないことで、APIからの不正なレスポンスがアプリケーション全体をクラッシュさせます。また、ループ内でJSONをパースしてパフォーマンスコストに気づかないこともあります。一度パースしてから結果をキャッシュしてください。さらに、JSON.parse("undefined")JSON.parse("") はいずれも有効なJSONではないためエラーをスローします。

ベストプラクティス:

JSON.parse() の周囲には常にtry/catchを使用してください。構造を盲目的に信頼するのではなく、パースされたデータを期待するスキーマに対して検証しましょう。JSONがネイティブにサポートしていない日付、BigInt値、その他の型を変換するためにreviver関数を使用してください。大きなJSON文字列をパースする際は、メモリ効率を高めるためにストリーミングパーサーを検討しましょう。

ユースケース

REST APIのfetch()呼び出しからJSONレスポンスをパースし、reviver関数を使用してISO 8601の日付文字列を自動的にJavaScript Dateオブジェクトに変換する。

試してみる — JSON Formatter

フルツールを開く