🤷

JSON.stringify() はちょっと深い

2023/04/09に公開

はじめに

こんにちは。
full-stack developerを目指しているShenです。
いつも使っているJSON.stringify()について語ろうと思います。

いつものユースケース

以下のコードを実行するとしたら、

const student = {
  id: 123456,
  name: 'Jack',
  gender: 'Male',
};
console.log(JSON.stringify(student));

結果は当然以下になります。Bear with me.

{"id":123456,"name":"Jack","gender":"Male"}

オブジェクトから一部だけ出力したい

例えば、上記のオブジェクトのidプロパティを出力したくない場合はどうしますか?
実際は、JSON.stringify()の2番目の引数はreplacerとなっています。

const student = {
  id: 123456,
  name: 'Jack',
  gender: 'Male',
};
console.log(JSON.stringify(student, ['name', 'gender']));

namegenderだけを出力することになりました。idreplacerの配列に含まれていないので、出力されません。

{"name":"Jack","gender":"Male"}

もしも、たくさんのプロパティを持っているオブジェクトが存在すれば、replacerの配列には出力したいプロパティを全部書くにはすごく効率が悪いと思うでしょう?そして、replacerを関数で渡して、条件に満たさないプロパティを除外することはできます。

以下仮のオブジェクトを対象とします。

const foo = {
  id: 123456,
  name: 'Jack',
  gender: 'Male',
  grade: 8,
  gpa: 3.6,
  unusedProperty1: 'foo1',
  unusedProperty2: 'foo2',
  unusedProperty3: 'foo3',
  unusedProperty4: 'foo4',
  unusedProperty5: 'foo5',
};

unusedProperty以外のプロパティを出力する場合、正規表現でundefinedをreturnすると、該当プロパティが出力されません。

console.log(
  JSON.stringify(foo, (key, value) =>
    key.match(/^unused/) ? undefined : value
  )
);

出力結果

{"id":123456,"name":"Jack","gender":"Male","grade":8,"gpa":3.6}

keyを条件にするだけではなく、valueも条件として使えます。
例えば、タイプがstringのプロパティだけを出力したい場合

console.log(
  JSON.stringify(foo, (key, value) =>
    typeof value === 'number' ? undefined : value
  )
);

出力結果

{"name":"Jack","gender":"Male","unusedProperty1":"foo1","unusedProperty2":"foo2","unusedProperty3":"foo3","unusedProperty4":"foo4","unusedProperty5":"foo5"}

第三引数のspace

上記の出力結果はかなり読みにくいです。spaceを追加して、出力する結果を読みやすくなりたい場合

const foo = {
 id: 123456,
 name: 'Jack',
 gender: 'Male',
 grade: 8,
 gpa: 3.6,
 unusedProperty5: { test: { foo: 'boo' } },
};
console.log(
 JSON.stringify(
   foo,
   (key, value) => (typeof value === 'number' ? undefined : value),
   1
 )
);

出力結果

{
 "name": "Jack",
 "gender": "Male",
 "unusedProperty5": {
  "test": {
   "foo": "boo"
  }
 }
}

あとは、第3引数はstringで渡せます。利用できる場面は思いつかないです・・・

const foo = {
  id: 123456,
  name: 'Jack',
  gender: 'Male',
  grade: 8,
  gpa: 3.6,
  unusedProperty5: { test: { foo: 'boo' } },
};
console.log(JSON.stringify(foo, undefined, '!@#$%^'));

出力結果

{
!@#$%^"id": 123456,
!@#$%^"name": "Jack",
!@#$%^"gender": "Male",
!@#$%^"grade": 8,
!@#$%^"gpa": 3.6,
!@#$%^"unusedProperty5": {
!@#$%^!@#$%^"test": {
!@#$%^!@#$%^!@#$%^"foo": "boo"
!@#$%^!@#$%^}
!@#$%^}
}

おわりに

かなり使っているメソッドでしたが、意外と知らなかったことが多かったですね。

Discussion