---
type: reference
language: javascript
slug: json/parse
title: "JSON.parse() と JSON.stringify()"
title_tag: "JavaScript JSON.parse と stringify — 消える値と例外"
summary: >
  JSON との変換で何が消え、何が形を変えるのかをまとめます。undefined や Map が黙って
  落ちる理由、循環参照で例外になる条件、reviver と toJSON の使い方を実行して確かめます。
description: >
  undefined や関数は鍵ごと消え、Map は空になります。例外も出ません。循環参照と BigInt だけが例外になる理由、深い複製に使ってはいけない理由まで扱います。
status: published
difficulty: 2
minutes: 10

versions:
  verified: "Node 22.22.3"
  since: "ES5"
  deprecated: null
  removed: null

sources:
  - title: "The JSON Object — ECMAScript® 2026 Language Specification"
    url: "https://tc39.es/ecma262/#sec-json-object"
  - title: "RFC 8259: The JavaScript Object Notation (JSON) Data Interchange Format"
    url: "https://www.rfc-editor.org/rfc/rfc8259"
  - title: "JSON.stringify — MDN"
    url: "https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify"

terms: [JSON, シリアライズ, 循環参照, reviver]

links:
  related:
    - javascript/errors/unexpected-token
    - javascript/how-to/object/merge
    - javascript/reference/collection/map-set
    - javascript/errors/unexpected-end-of-json

content_updated_at: 2026-09-08
published_at: 2026-09-08
---

`JSON.stringify()` は値を[key:文字列]にし、`JSON.parse()` は文字列を値に戻します。

```js run
const data = { name: 'あ', n: 1, ok: true, list: [1, 2] };

console.log(JSON.stringify(data));
console.log(JSON.parse('{"a":1}'));
```
```output
{"name":"あ","n":1,"ok":true,"list":[1,2]}
{ a: 1 }
```

第3引数を渡すと、[fn:読みやすく字下げ]されます。

```js run
console.log(JSON.stringify({ a: 1, b: [2] }, null, 2));
```
```output
{
  "a": 1,
  "b": [
    2
  ]
}
```

**人が読むときだけ使ってください。** 通信量が増えます。

## 黙って消えるもの

**ここがいちばん事故になります。** 例外は出ません。

```js run
const data = {
  u: undefined,
  f() {},
  s: Symbol('x'),
  n: NaN,
  i: Infinity,
  d: new Date('2026-09-08'),
  m: new Map([['k', 1]]),
};

console.log(JSON.stringify(data));
```
```output
{"n":null,"i":null,"d":"2026-09-08T00:00:00.000Z","m":{}}
```

| 入れたもの | どうなるか |
|---|---|
| `undefined` | [bad:鍵ごと消える] |
| 関数 | [bad:鍵ごと消える] |
| `Symbol` | [bad:鍵ごと消える] |
| `NaN` / `Infinity` | `null` |
| `Date` | **文字列**になる（戻すと `Date` ではない） |
| `Map` / `Set` | [bad:空のオブジェクト] |

JSON にはこれらを表す書き方がありません。**JSON は JavaScript の一部ではない**からです。

配列の中では、消えるかわりに `null` になります。

```js run
console.log(JSON.stringify({ a: 1, b: undefined }));
console.log(JSON.stringify([1, undefined, 2]));
```
```output
{"a":1}
[1,null,2]
```

**配列は長さを保たないといけない**ので、詰められずに `null` が入ります。

### 戻り値が文字列とは限らない

```js run
console.log(JSON.stringify(undefined));
console.log(typeof JSON.stringify(undefined));
console.log(JSON.stringify(() => {}));
```
```output
undefined
undefined
undefined
```

**文字列ではなく `undefined` が返ります。**
`JSON.stringify(値).length` のような書き方は、ここで落ちます。

## 例外になるもの

消えずに[bad:例外を投げる]ものが2つあります。

```js run
const data = { name: 'あ' };
data.self = data;

try {
  JSON.stringify(data);
} catch (error) {
  console.log(error.name);
}

try {
  JSON.stringify({ n: 1n });
} catch (error) {
  console.log(error.name);
}
```
```output
TypeError
TypeError
```

- [type:循環参照]（自分を含む構造）
- `BigInt`

[dim:例外の文言は処理系によって違います。ここでは種類（`name`）だけを見ています。]

## 読めない文字列は `SyntaxError`

```js run
for (const text of ["{'a':1}", '', '{"a":1,}']) {
  try {
    JSON.parse(text);
  } catch (error) {
    console.log(error.name);
  }
}
```
```output
SyntaxError
SyntaxError
SyntaxError
```

JSON は JavaScript のオブジェクトリテラルより[key:厳しい]決まりです。

| JavaScript では書ける | JSON では |
|---|---|
| `{ 'a': 1 }` | [bad:単引用符は不可] |
| `{ a: 1 }` | [bad:引用符なしの鍵は不可] |
| `{ "a": 1, }` | [bad:末尾のカンマは不可] |
| `// コメント` | [bad:コメントは不可] |

文言と読み方は、エラーのページで詳しく扱っています。
→ [SyntaxError: Unexpected token](/ja/javascript/errors/unexpected-token/)

**外から来た文字列は、必ず `try` で囲んでください。**

```js run
function safeParse(text) {
  try {
    return { ok: true, value: JSON.parse(text) };
  } catch {
    return { ok: false, value: null };
  }
}

console.log(safeParse('{"a":1}'));
console.log(safeParse('こわれている'));
```
```output
{ ok: true, value: { a: 1 } }
{ ok: false, value: null }
```

## オブジェクト以外も扱える

JSON はオブジェクトだけの形式ではありません。

```js run
console.log(JSON.parse('1'), JSON.parse('"あ"'), JSON.parse('true'), JSON.parse('null'));
console.log(JSON.stringify('あ'));
```
```output
1 あ true null
"あ"
```

文字列を `stringify()` すると、**引用符が付いた文字列**になります。
[bad:二重に変換して引用符が増える]のは、よくある間違いです。

## 変換のしかたを変える

### `toJSON()` を持たせる

オブジェクト側に `toJSON()` があれば、その戻り値が使われます。

```js run
class Money {
  constructor(yen) {
    this.yen = yen;
  }

  toJSON() {
    return this.yen + '円';
  }
}

console.log(JSON.stringify({ price: new Money(300) }));
```
```output
{"price":"300円"}
```

`Date` が文字列になるのも、`Date` が `toJSON()` を持っているからです。

### 第2引数で選ぶ・変える

```js run
console.log(JSON.stringify({ a: 1, b: 2 }, ['a']));
console.log(JSON.stringify({ a: 1, b: 2 }, (key, value) => (key === 'b' ? undefined : value)));
```
```output
{"a":1}
{"a":1}
```

配列を渡せば[key:その鍵だけ]、関数を渡せば[fn:値を書き換えられます]。
`undefined` を返すと、その鍵は出力されません。

**パスワードやトークンを外す用途に使えます。**

### 読み込むときに戻す

`JSON.parse()` の第2引数（[type:reviver]）で、値を作り直せます。

```js run
const json = '{"date":"2026-09-08T00:00:00.000Z","n":1}';

const parsed = JSON.parse(json, (key, value) => (key === 'date' ? new Date(value) : value));

console.log(parsed.date instanceof Date);
console.log(parsed.date.toISOString());
```
```output
true
2026-09-08T00:00:00.000Z
```

## よくある間違い

### 深い複製に使う

```js bad
const src = { d: new Date('2026-09-08'), u: undefined };
const copy = JSON.parse(JSON.stringify(src));

console.log(typeof copy.d);
console.log('u' in copy);
```
```output
string
false
```

**複製はできます。ですが中身が変わります。**
`Date` は文字列になり、`undefined` の鍵は消えます。

`structuredClone()` を使ってください。

```js run
const src = { d: new Date('2026-09-08'), u: undefined };
const copy = structuredClone(src);

console.log(copy.d instanceof Date);
console.log('u' in copy);
```
```output
true
true
```

→ [オブジェクトを結合する](/ja/javascript/how-to/object/merge/)

### 鍵の順番を当てにする

`JSON.stringify()` は、オブジェクトの[key:鍵の順]をそのまま出します。
**ですがオブジェクトの鍵の順は、整数に見える鍵が先に来ます。**

文字列を比べて同じかどうか判定する用途（署名・キャッシュの鍵）では、
[bad:順番の違いで別物と判定されます]。**鍵を並べ替えてから変換してください。**

## まとめ

- `undefined` / 関数 / `Symbol` は[bad:黙って消える]。配列の中では `null`
- `NaN` と `Infinity` は `null`。`Map` / `Set` は `{}`
- [type:循環参照]と `BigInt` は[em:例外]
- `JSON.stringify()` は**文字列以外を返すことがある**（`undefined`）
- 外から来た文字列は必ず `try` で囲む
- **深い複製には使わない。** `structuredClone()` を使う
