JavaScriptのJSON.stringify()

JavaScriptのJSON.stringify()をマスターしましょう。構文、replacer関数、インデント、undefined・日付・循環参照などの特殊値の処理方法を包括的に解説します。

Conversion

詳細な説明

JSON.stringify() は、JavaScript値をJSON形式の文字列に変換するための組み込みメソッドです。Web開発で最も頻繁に使用されるメソッドの一つであり、APIへのデータ送信、localStorageへのデータ保存、ログ出力のためのオブジェクトシリアライズに不可欠です。

メソッドシグネチャ:

JSON.stringify(value, replacer?, space?)
  • value: シリアライズするJavaScript値(object、array、プリミティブ)
  • replacer: プロパティをフィルタリング/変換するオプションの関数または配列
  • space: インデント用のオプションの数値(1-10)または文字列

基本的な使い方:

JSON.stringify({ name: "Alice", age: 30 })
// '{"name":"Alice","age":30}'

JSON.stringify({ name: "Alice" }, null, 2)
// '{\n  "name": "Alice"\n}'

replacerパラメータ:

replacer関数は各key-valueペアを受け取り、値を変換できます:

JSON.stringify(data, (key, value) => {
  if (typeof value === 'string') return value.toUpperCase();
  return value;
});

配列のreplacerはホワイトリストとして機能し、指定されたキーのみを含めます:

JSON.stringify(user, ['name', 'email']); // only these keys

暗黙に削除または変換される値:

  • undefined、関数、Symbolはobjectから省略される
  • arrayでは null になる: [1, undefined, 3] -> [1,null,3]
  • Date オブジェクトは .toISOString() メソッド経由でシリアライズされる
  • NaNInfinitynull になる
  • BigIntTypeError をスローする(自分で変換する必要あり)
  • 循環参照は TypeError をスローする

toJSON()メソッド:

オブジェクトに toJSON() メソッドがある場合、JSON.stringify() はそれを呼び出し、オブジェクト自体ではなく戻り値をシリアライズします。Date オブジェクトがISO文字列を生成するのはこの仕組みです。独自のクラスで toJSON() を定義してシリアライズを制御できます:

class User {
  constructor(name, passwordHash) {
    this.name = name;
    this.passwordHash = passwordHash;
  }
  toJSON() {
    return { name: this.name }; // exclude sensitive data
  }
}

開発者がよくやるミス:

最も重大なミスは、JSON.stringify() がすべてのデータを保持すると仮定することです。undefined 値を持つプロパティは暗黙に消失し、JSONを介したデータのラウンドトリップ時に微妙なバグを引き起こす可能性があります。もうひとつのミスは循環参照の処理を忘れることで、無用な TypeError でクラッシュします。flatted ライブラリやカスタムreplacerを使用してサイクルを処理してください。また、すでにstringify済みの値をさらにstringifyしてしまい、二重エンコードされたJSON("\"{\\\"key\\\":\\\"value\\\"}\")を生成することもあります。

ベストプラクティス:

stringify前にオブジェクト内のデータ型を常に考慮してください。パスワードやトークンなどの機密フィールドを除外するためにreplacerを使用しましょう。ラウンドトリップで生き残る必要があるデータの場合は、JSON.parse(JSON.stringify(data)) が期待通りの結果を生むかテストしてください。BigIntと循環参照のエラーは明示的にハンドリングしましょう。

ユースケース

fetch()のPOSTリクエストのボディとしてJavaScriptオブジェクトをシリアライズする際、replacer関数を使用して機密フィールドをフィルタリングしてContent-Type: application/jsonで送信する。

試してみる — JSON Formatter

フルツールを開く