JSON.stringify() メソッドは、ある JavaScript のオブジェクトや値を JSON 文字列に変換します。置き換え関数を指定して値を置き換えたり、置き換え配列を指定して指定されたプロパティのみを含むようにしたりすることもできます。
この対話型サンプルのソースファイルは GitHub リポジトリに格納されています。対話型サンプルプロジェクトに協力したい場合は、 https://github.com/mdn/interactive-examples をクローンしてプルリクエストを送信してください。
構文
JSON.stringify(value[, replacer[, space]])
引数
value- JSON 文字列に変換する値です。
replacerOptional- 文字列化の手順の挙動を変更する関数、または値のオブジェクトを JSON 文字列に含めるプロパティを選択するホワイトリストとして機能する
StringとNumberオブジェクトの配列。もしこの値がnullであるか提供されなかった場合は、結果の文字列にオブジェクトのすべてのプロパティが含まれます。 spaceOptional- 出力する JSON 文字列に可読性を目的に空白を挿入するために使う
StringまたはNumberオブジェクトです。これが
Numberのときは、空白として使う空白文字の数を示します。この数の上限は10です (それより大きい数値は、単に10となります)。 1 より小さい値は空白を使わないことを示します。これが
Stringのときは、その文字列 (10文字より長い場合はその最初の10文字) が空白として使われます。もしこの引数が提供されない (または null である) 場合は、空白は使用されません。
返値
与えられた値を表現する JSON 文字列。
例外
TypeError("cyclic object value") 例外は、循環参照が見つかった時に発生します。TypeError("BigInt value can't be serialized in JSON") 例外は、BigInt値を文字列化しようとしたときに発生します。
説明
JSON.stringify() は値をそれを表す JSON 表記に変換します。
- 値が
toJSON()メソッドを持っている場合は、データがどのようにシリアライズされるかを定義する必要があります。 Boolean、Number、Stringの各オブジェクトは、文字列化の際に慣習的な変換セマンティクスに従い、対応するプリミティブ値に変換されます。- 変換の際に
undefined、 関数 (Function)、シンボル (Symbol) は有効な JSON 値ではありません。変換中にそのような値に遭遇した場合は、 (オブジェクトの中で発見された場合は) 省略されたり、 (配列の中で見つかった場合は)nullに変換されたりします。JSON.stringifyはJSON.stringify(function(){})やJSON.stringify(undefined)のように「純粋」な値を渡した場合にundefinedを返すことがあります。 - シンボル (
Symbol) がキーとなっているプロパティはすべて、replacer関数を使用する場合でも完全に無視されます。 Dateのインスタンスは文字列を返すtoJSON()を実装しています (date.toISOString()と同じです)。したがって、これらは文字列として扱われます。InfinityおよびNaNの数値は、nullの値と同様、すべてnullと見なされます。- その他のすべての
Objectのインスタンスは (Map,Set,WeakMap,WeakSetを含め)、列挙可能なプロパティのみがシリアライズされます。
JSON.stringify({}); // '{}'
JSON.stringify(true); // 'true'
JSON.stringify('foo'); // '"foo"'
JSON.stringify([1, 'false', false]); // '[1,"false",false]'
JSON.stringify([NaN, null, Infinity]); // '[null,null,null]'
JSON.stringify({ x: 5 }); // '{"x":5}'
JSON.stringify(new Date(2006, 0, 2, 15, 4, 5))
// '"2006-01-02T15:04:05.000Z"'
JSON.stringify({ x: 5, y: 6 });
// '{"x":5,"y":6}'
JSON.stringify([new Number(3), new String('false'), new Boolean(false)]);
// '[3,"false",false]'
// 文字列がキーとなった配列要素は列挙可能ではなく、 JSON では意味をなさない
let a = ['foo', 'bar'];
a['baz'] = 'quux'; // a: [ 0: 'foo', 1: 'bar', baz: 'quux' ]
JSON.stringify(a);
// '["foo","bar"]'
JSON.stringify({ x: [10, undefined, function(){}, Symbol('')] });
// '{"x":[10,null,null,null]}'
// 標準データ構造
JSON.stringify([new Set([1]), new Map([[1, 2]]), new WeakSet([{a: 1}]), new WeakMap([[{a: 1}, 2]])]);
// '[{},{},{},{}]'
// 型付き配列
JSON.stringify([new Int8Array([1]), new Int16Array([1]), new Int32Array([1])]);
// '[{"0":1},{"0":1},{"0":1}]'
JSON.stringify([new Uint8Array([1]), new Uint8ClampedArray([1]), new Uint16Array([1]), new Uint32Array([1])]);
// '[{"0":1},{"0":1},{"0":1},{"0":1}]'
JSON.stringify([new Float32Array([1]), new Float64Array([1])]);
// '[{"0":1},{"0":1}]'
// toJSON()
JSON.stringify({ x: 5, y: 6, toJSON(){ return this.x + this.y; } });
// '11'
// シンボル:
JSON.stringify({ x: undefined, y: Object, z: Symbol('') });
// '{}'
JSON.stringify({ [Symbol('foo')]: 'foo' });
// '{}'
JSON.stringify({ [Symbol.for('foo')]: 'foo' }, [Symbol.for('foo')]);
// '{}'
JSON.stringify({ [Symbol.for('foo')]: 'foo' }, function(k, v) {
if (typeof k === 'symbol') {
return 'a symbol';
}
});
// undefined
// enumerable でないプロパティ:
JSON.stringify( Object.create(null, { x: { value: 'x', enumerable: false }, y: { value: 'y', enumerable: true } }) );
// '{"y":"y"}'
// BigInt の値は例外が発生
JSON.stringify({x: 2n});
// TypeError: BigInt value can't be serialized in JSON
replacer 引数
replacer 引数は関数または配列です。
関数については、キーと文字列化される値の 2 つの引数を取ります。キーをもつオブジェクトが replacer の this パラメータとして提供されます。
最初に文字列化されるオブジェクトを表す空のキーで呼ばれ、それからそれぞれの文字列化されるオブジェクトや配列のプロパティについて呼ばれます。
JSON 文字列に加える値を、次のように返します。
Numberを返すと、 JSON 文字列に追加されるときにその数値に対応する文字列がプロパティの値として使用されます。Stringを返すと、 JSON 文字列に追加されるときにその文字列がプロパティの値として使用されます。Booleanを返すと、 JSON 文字列に追加されるときに"true" または "false" が適切にプロパティの値として使用されます。nullを返すと、nullが JSON 文字列に追加されます。- その他のオブジェクトを返した場合、そのオブジェクトは再帰的に JSON 文字列に文字列化されます。その時それぞれのプロパティに対して、そのオブジェクトが関数である場合を除いて
replacer関数を呼びます。関数である場合は JSON 文字列には何も追加されません。 undefinedを返した場合、そのプロパティは出力する JSON 文字列には含まれません。
メモ: replacer 関数を使用して配列から値を削除することはできません。 undefined や関数を返すと、代わりに null が使用されます。
メモ: replacer が、オブジェクトが初期状態であるか、空文字列のキーを持つプロパティであるかを判別するには (どちらの場合もキーが空文字列になり、オブジェクトが値になる可能性があるので)、繰り返し回数を追跡しておく必要があります (繰り返しが1回を超えた場合、空文字列のキーであることが分かります)。
関数を使った例
function replacer(key, value) {
// Filtering out properties
if (typeof value === 'string') {
return undefined;
}
return value;
}
var foo = {foundation: 'Mozilla', model: 'box', week: 45, transport: 'car', month: 7};
JSON.stringify(foo, replacer);
// '{"week":45,"month":7}'
配列を使った例
replacer が配列である場合、その配列の値は結果の JSON 文字列に含めるプロパティの名前を示します。
JSON.stringify(foo, ['week', 'month']);
// '{"week":45,"month":7}', "week" と "month" プロパティだけが保持される
space 引数
space 引数で最終的な文字列でのスペーシングを調整できます。
- 数値であれば、レベルの階層がそれぞれその数の空白文字(最大10文字)でインデントされます。
- 文字列であれば、レベル階層がそれぞれこの文字列(またはその最初の10文字)でインデントされます。
JSON.stringify({ a: 2 }, null, ' ');
// '{
// "a": 2
// }'
タブ文字を使うと、標準的な表示の整形と同様になります。
JSON.stringify({ uno: 1, dos: 2 }, null, '\t');
// returns the string:
// '{
// "uno": 1,
// "dos": 2
// }'
toJSON() の挙動
文字列化されるオブジェクトに toJSON という名前の値に関数を持ったプロパティがある場合、その toJSON() メソッドで JSON の文字列化の挙動をカスタマイズできます。シリアライズされるオブジェクトの代わりに、その toJSON() メソッドが呼び出されたときの返値がシリアライズされます。 JSON.stringify() は toJSON に以下のどれか1つの引数をつけて呼び出します。
- このオブジェクトがプロパティの値であった場合は、プロパティ名
- 配列内の値で会った場合は、配列のインデックス番号を文字列で
JSON.stringify()がこのオブジェクトに対して直接呼び出された場合は、空文字列
例
var obj = {
data: 'data',
toJSON (key) {
if (key)
return `Now I am a nested object under key '${key}'`;
else
return this;
}
};
JSON.stringify(obj);
// '{"data":"data"}'
JSON.stringify({ obj })
// '{"obj":"Now I am a nested object under key 'obj'"}'
JSON.stringify([ obj ])
// '["Now I am a nested object under key '0'"]'
循環参照をシリアライズする時の JSON.stringify() に関する問題
JSON 形式はオブジェクト参照に対応していないため (IETF 草稿はありますが)、循環参照のあるオブジェクトをエンコードしようとすると TypeError が発生します。
const circularReference = {};
circularReference.myself = circularReference;
// 循環参照をシリアライズすると "TypeError: cyclic object value" が発生
JSON.stringify(circularReference);
循環参照をシリアライズするためには、これに対応したライブラリを使用したり (Douglas Crockford による cycle.js など)、自分自身で解決策を実装したりする方法があります。循環参照を探索してシリアライズされた値に置き換える (または削除する) 必要があるでしょう。
JavaScript としての使用に際してのそのままの JSON.stringify の問題
従来、 JSON は JavaScript の完全に厳密なサブセットではありませんでした。文字コードポイント U+2028 LINE SEPARATOR (改行) と U+2029 PARAGRAPH SEPARATOR (改段落) は JSON テキスト内の文字列リテラルやプロパティ名に使用することができます。しかし、 JavsScript のテキスト内で同様の文脈では使用することができません -- Unicode エスケープを使用した \u2028 および \u2029 しか使うことができません。これは最近変更され、どちらのコードポイントも JSON と JavaScript の両方の文字列で使用することができるようになりました。
したがって、古い JavaScript エンジンとの互換性が必要な場合は、 JSON.stringify から返された文字列を JavaScript の文字列に代入するために、直接 eval や new Function に渡したり、 JSONP URL の一部として用いたりするのは危険です。次のユーティリティを使用することができます。
function jsFriendlyJSONStringify (s) {
return JSON.stringify(s).
replace(/\u2028/g, '\\u2028').
replace(/\u2029/g, '\\u2029');
}
var s = {
a: String.fromCharCode(0x2028),
b: String.fromCharCode(0x2029)
};
try {
eval('(' + JSON.stringify(s) + ')');
} catch (e) {
console.log(e); // "SyntaxError: unterminated string literal"
}
// catch する必要はない
eval('(' + jsFriendlyJSONStringify(s) + ')');
// Firefox での console.log はコンソールにログ出力をする場合
// Unicode エスケープを解除するので、alert を使う
alert(jsFriendlyJSONStringify(s)); // {"a":"\u2028","b":"\u2029"}
メモ: 配列以外のオブジェクトのプロパティでは、特定の順番で文字列化されることは保証されていません。文字列化された同じオブジェクトの中でプロパティの順番に依存しないようにしてください。
var a = JSON.stringify({ foo: "bar", baz: "quux" })
//'{"foo":"bar","baz":"quux"}'
var b = JSON.stringify({ baz: "quux", foo: "bar" })
//'{"baz":"quux","foo":"bar"}'
console.log(a !== b) // true
// 一部の記憶関数は JSON.stringify を使用して引数をシリアライズしており、
// 上記のような同じオブジェクトに出会った時にキャッチし損ねることがあります
localStorage で JSON.stringify() を使った例
ユーザーが作成したオブジェクトを格納し、ブラウザーが閉じた後に復元できるようにしたい場合は以下の例が JSON.stringify() を適用した模範例です。
// JSON の一例を作成
var session = {
'screens': [],
'state': true
};
session.screens.push({ 'name': 'screenA', 'width': 450, 'height': 250 });
session.screens.push({ 'name': 'screenB', 'width': 650, 'height': 350 });
session.screens.push({ 'name': 'screenC', 'width': 750, 'height': 120 });
session.screens.push({ 'name': 'screenD', 'width': 250, 'height': 60 });
session.screens.push({ 'name': 'screenE', 'width': 390, 'height': 120 });
session.screens.push({ 'name': 'screenF', 'width': 1240, 'height': 650 });
// JSON.stringify() で JSON 文字列に変換してから
// session の名前で localStorage に保存
localStorage.setItem('session', JSON.stringify(session));
// JSON.stringify() で生成されて localStorage に保存された文字列を
// 再び JSON オブジェクトに変換する方法の例
var restoredSession = JSON.parse(localStorage.getItem('session'));
// ここで変数 restoredSession には localStorage に保存されていた
// オブジェクトが入っている
console.log(restoredSession);
Well-formed JSON.stringify()
well-formed JSON.stringify 仕様を実装しているエンジンは、サロゲート文字 -- U+D800 から U+DFFF までのすべてのコードポイント -- を、リテラルではなく Unicode エスケープシーケンスを使用して文字列化します。この変更前は、入力にサロゲート文字が含まれている場合、 JSON.stringify はサロゲート文字をそのまま出力していました。このような文字列は妥当な UTF-8 または UTF-16 でエンコードされていませんでした。
JSON.stringify("\uD800"); // '"�"'
しかし、この変更で JSON.stringify は lone surrogates を JSON エスケープシーケンスによって表すようになり、妥当な UTF-8 または UTF-16 でエンコードすることができるようになりました。
JSON.stringify("\uD800"); // '"\\ud800"'
この変更では、サロゲート文字の Unicode エスケープをサロゲート文字と同一のものとして扱うため、 JSON.stringify の結果を、 JSON テキストを妥当である限りどのようなものでも受け付ける JSON.parse のような API に渡したときに後方互換性があります。 JSON.stringify の結果を直接解析する場合のみ、 JSON.stringify がこれらのコードポイントに対して2通りのエンコーディングをする可能性があることに注意して扱う必要があります。
仕様書
| 仕様書 | 状態 | 備考 |
|---|---|---|
| ECMAScript (ECMA-262) JSON.stringify の定義 |
現行の標準 | |
| ECMAScript 2015 (6th Edition, ECMA-262) JSON.stringify の定義 |
標準 | |
| ECMAScript 5.1 (ECMA-262) JSON.stringify の定義 |
標準 | 初回定義。JavaScript 1.7 で実装。 |
ブラウザーの互換性
| デスクトップ | モバイル | サーバー | |||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
stringify | Chrome 完全対応 3 | Edge 完全対応 12 | Firefox 完全対応 3.5 | IE 完全対応 8 | Opera 完全対応 10.5 | Safari 完全対応 4 | WebView Android 完全対応 ≤37 | Chrome Android 完全対応 18 | Firefox Android 完全対応 4 | Opera Android 完全対応 11 | Safari iOS 完全対応 4 | Samsung Internet Android 完全対応 1.0 | nodejs 完全対応 あり |
| Well-formed JSON.stringify | Chrome 完全対応 72 | Edge 完全対応 79 | Firefox 完全対応 64 | IE 未対応 なし | Opera 完全対応 60 | Safari 完全対応 12.1 | WebView Android 完全対応 72 | Chrome Android 完全対応 72 | Firefox Android 完全対応 64 | Opera Android 完全対応 50 | Safari iOS 完全対応 12.2 | Samsung Internet Android 未対応 なし | nodejs 未対応 なし |
凡例
- 完全対応
- 完全対応
- 未対応
- 未対応
関連情報
JSON.parse()- cycle.js – Introduces two functions:
JSON.decycleandJSON.retrocycle. These allow encoding and decoding of cyclical structures and DAGs into an extended and retrocompatible JSON format.