JSON.parse()とJSON.stringify()は文字列から値を読む処理と値を文字列へ変える処理を分ける
公開日: 執筆:佐藤
JSON.parse()は、JSON形式の文字列をJavaScriptの値へ変えます。JSON.stringify()は反対に、JavaScriptの値をJSON形式の文字列へ変えます。
二つを使い分ける基準は、変換前の値が文字列かどうかです。保存先や通信先から受け取ったJSON文字列を読むならparse()、objectやarrayを文字列として渡すならstringify()を使います。
parse()はJSON文字列からJavaScriptの値を作る
ECMAScript 5.1のJSON.parse()仕様は、JSON形式の文字列を解析し、ECMAScriptの値を作る処理を定めています。object、array、string、number、boolean、nullを、それぞれ対応する値として受け取れます。
次は、変換方向を示すための仮例です。
var text = '{"service":"資料請求","enabled":true,"count":3}';
var settings = JSON.parse(text);
settings.service; // "資料請求"
settings.enabled; // true
settings.count; // 3
textは一つの文字列です。JSON.parse(text)を実行した後のsettingsはobjectなので、プロパティを値として読めます。
すでにobjectである値へJSON.parse()を使う必要はありません。どの処理が文字列を受け取り、どの処理からobjectとして扱うかを、変数名と処理の境界で分けます。
stringify()はJavaScriptの値からJSON文字列を作る
ECMAScript 5.1のJSON.stringify()仕様は、ECMAScriptの値を表すJSON形式の文字列を返す処理を定めています。
var settings = {
service: '資料請求',
enabled: true,
count: 3
};
var text = JSON.stringify(settings);
typeof text; // "string"
settingsはobject、textは文字列です。保存や通信の仕組みが文字列を受け取るなら、objectのまま渡さず、必要なプロパティを決めてからJSON.stringify()で変換します。
| 変換前 | 使う処理 | 変換後 |
|---|---|---|
| JSON形式の文字列 | JSON.parse() |
JavaScriptの値 |
| JavaScriptの値 | JSON.stringify() |
JSON形式の文字列 |
関数名を覚えるより、変換前と変換後の型をコード上で確認するほうが間違いを減らせます。
JSONの文法に合わない文字列はSyntaxErrorになる
JSONは、JavaScriptのobject literalと同じ書き方をすべて許すわけではありません。objectのプロパティ名と文字列は二重引用符で囲み、最後の要素の後ろへ余分なcommaを置きません。
JSON.parse("{'enabled':true}");
// JSON grammarに合わないためSyntaxError
JSON.parse('{"enabled":true,}');
// JSON grammarに合わないためSyntaxError
JSON.parse()は、文字列がJSON grammarに合わなければSyntaxErrorを投げます。外部から受け取る文字列は、成功する前提で次の処理へ渡さず、失敗した場合の扱いを決めます。
function parseSettings(text) {
var value;
try {
value = JSON.parse(text);
} catch (error) {
return null;
}
if (value === null || typeof value !== 'object') {
return null;
}
if (typeof value.enabled !== 'boolean') {
return null;
}
return value;
}
この仮例は、文法エラーと期待する構造の違いを分けます。JSON.parse()が成功しても、必要なプロパティがあることや、その値が想定した型であることまでは保証しません。
stringify()はすべてのobjectを変換できるわけではない
JSON.stringify()へ渡す前にも、値の構造を確認します。objectが自分自身をたどる循環参照を持つ場合、変換処理はTypeErrorになります。
var data = {};
data.self = data;
JSON.stringify(data);
// TypeError
関数など、JSONの値として表せないものもあります。画面の状態を丸ごと渡そうとせず、保存または通信に必要なstring、number、boolean、null、object、arrayだけで新しいdataを組み立てます。
変換できたことと、受け取り側がその構造を理解できることも別です。プロパティ名、値の型、必須項目、版を双方で決めなければ、正しいJSON文字列でも処理できません。
reviverとreplacerは変換規則が必要なときだけ使う
JSON.parse()の第二引数にはreviverを指定でき、解析したkeyとvalueを順に確認して、値を変換または除外できます。JSON.stringify()の第二引数にはreplacerを指定でき、functionまたはproperty名のarrayで出力内容を変えられます。
var settings = {
service: '資料請求',
enabled: true,
internalNote: '確認用'
};
var publicText = JSON.stringify(
settings,
['service', 'enabled'],
2
);
この例では、serviceとenabledだけを文字列へ含め、第三引数の2で読みやすい字下げを加えます。単純な変換に規則を増やす必要はありません。除外するpropertyが決まっているなら、名前と理由をdataの仕様として残します。
保存前と読込後でdataの責任を分ける
JSON.stringify()を実行する側は、どのpropertyを外へ出すかを決めます。JSON.parse()を実行する側は、受け取った値の型と必須propertyを確認します。両方を「JSONへ変換する処理」とまとめると、入力検査の担当が曖昧になります。
実装を引き継ぐときは、次の四点を残します。
- JSON文字列を作る処理と、その直前のdata構造
- JSON文字列を受け取る処理と、失敗時の扱い
- 必須property、値の型、許可する範囲
- propertyを追加または削除したときの版の扱い
最初の一手は、JSONを扱う一箇所を選び、変換前と変換後の値へtypeofを付けて確認することです。文字列から値へ進むならJSON.parse()、値から文字列へ進むならJSON.stringify()を置き、その直後に必要な構造を検査します。
関連記事

