reviver / replacer 関数の活用

JSON.parse() と JSON.stringify() には、変換処理をカスタマイズできる関数を渡すことができます。reviver と replacer を使いこなすと、Date の変換や特定プロパティの除外など、高度な JSON 処理が可能になります。

reviver 関数(JSON.parse の第2引数)

reviver 関数は、JSON.parse() の変換中に各キーと値のペアに対して呼び出されます。

const json = '{"name": "田中", "age": 25}';

const obj = JSON.parse(json, (key, value) => {
  console.log(`${key}: ${value}`);
  return value;
});

// 出力:
// name: 田中
// age: 25
// : [object Object]  ← 最後にルートオブジェクト

Date オブジェクトの復元

JSON では Date は文字列になってしまいますが、reviver を使えば Date オブジェクトとして復元できます。

const json = '{"event": "会議", "date": "2024-03-15T10:00:00.000Z"}';

const obj = JSON.parse(json, (key, value) => {
  // ISO形式の日付文字列をDateに変換
  if (typeof value === "string" && /^\d{4}-\d{2}-\d{2}T/.test(value)) {
    return new Date(value);
  }
  return value;
});

console.log(obj.date instanceof Date); // true
console.log(obj.date.getFullYear());   // 2024

値の変換

reviver で値を変換することもできます。

const json = '{"price": "1500", "quantity": "3"}';

// 数値文字列を数値に変換
const obj = JSON.parse(json, (key, value) => {
  if (typeof value === "string" && /^\d+$/.test(value)) {
    return parseInt(value, 10);
  }
  return value;
});

console.log(typeof obj.price); // "number"

replacer 関数(JSON.stringify の第2引数)

replacer 関数は、JSON.stringify() の変換中に各キーと値のペアに対して呼び出されます。undefined を返すと、そのプロパティは出力から除外されます。

const user = {
  name: "田中",
  password: "secret123",
  email: "tanaka@example.com"
};

// パスワードを除外
const json = JSON.stringify(user, (key, value) => {
  if (key === "password") {
    return undefined;
  }
  return value;
});

console.log(json);
// '{"name":"田中","email":"tanaka@example.com"}'
reviver(parse)

パース時に値を変換・復元する

replacer(stringify)

文字列化時に値を変換・除外する

配列による replacer

replacer には配列を渡すこともでき、その場合は指定したキーのみが出力されます。

const user = {
  id: 1,
  name: "田中",
  email: "tanaka@example.com",
  password: "secret",
  createdAt: "2024-01-01"
};

// 指定したキーのみ出力
const json = JSON.stringify(user, ["id", "name", "email"]);
console.log(json);
// '{"id":1,"name":"田中","email":"tanaka@example.com"}'

センシティブデータのマスキング

ログ出力時にパスワードなどをマスキングする例です。

function safeStringify(obj) {
  const sensitiveKeys = ["password", "token", "secret", "apiKey"];
  
  return JSON.stringify(obj, (key, value) => {
    if (sensitiveKeys.includes(key)) {
      return "***REDACTED***";
    }
    return value;
  }, 2);
}

const config = {
  url: "https://api.example.com",
  apiKey: "sk-1234567890",
  password: "secret123"
};

console.log(safeStringify(config));

カスタム型の変換

独自クラスのインスタンスを JSON に変換し、復元する例です。

class User {
  constructor(name, age) {
    this.name = name;
    this.age = age;
    this._type = "User";
  }
  
  greet() {
    return `Hello, ${this.name}!`;
  }
}

// stringify 時にメタ情報を保持
const json = JSON.stringify(new User("田中", 25));

// parse 時に復元
const obj = JSON.parse(json, (key, value) => {
  if (value && value._type === "User") {
    return new User(value.name, value.age);
  }
  return value;
});

console.log(obj instanceof User); // true
console.log(obj.greet());         // "Hello, 田中!"

reviver と replacer を活用することで、JSON の標準機能を超えた柔軟なデータ変換が実現できます。