JSONについて勘違いしていたこと

[Code Polaris 2021 アドベントカレンダー](https://qiita.com/advent-calendar/2021/code-polaris) 3日目の記事です。

# 概要
APIレスポンスを`jq`コマンドで加工するにあたり、JSONのデータ型への理解不足があったので調べたことをまとめました。

これまで以下3例の形だけがJSONだと勘違いしていました。


```json
[
  {
    "name": "Ken",
    "age": 15
  },
  {
    "name": "Mary",
    "age": 18
  }
]
```

```json
{
  "person1": {
    "name": "Ken",
    "age": 15
  },
  "person2": {
    "name": "Mary",
    "age": 18
  }
}
```

```json
{
  "person1":["Ken", 15],
  "person2": ["Mary", 18]
}
```



# JSONとは
* JavaScript Object Notationの略。
    * Notation: 表記、記法
* 軽量のデータ交換形式
* (ヒトからすれば配列やオブジェクト等に見えるが)、プログラムから見たら**ただの文字列**
    * `JSON.parse()`をすることで、JavaScriptで意味のあるデータ型に解釈される(メモリに配置されプログラムから使える状態になる)。
    * `JSON.stringify()`はメモリに配置されてるデータをJSON文字列に変換する(他のプログラムにデータを渡したり、ストレージにデータを保存する時に使う)。

> JSON では文字列とプロパティ名をダブルクォートで括る必要があります。シングルクォートは、JSON 文字列全体を囲む以外では無効です。

> (中略)

> JSON は配列やオブジェクトに限らず JSON内に含むことができるデータ型のデータだけでも有効な JSON となります。 例えば、1 つだけの文字列や数値も有効な JSON です。
引用元： [JSON データの操作](https://developer.mozilla.org/ja/docs/Learn/JavaScript/Objects/JSON#other_notes)




# JSONが用意してるデータ型の種類
以下の例はすべてJSONとして正しい形になります。

## 文字列
```json
"hello"
```


## 数値
```json
1
```

## boolean
```json
true
```

```json
false
```


## null
```json
null
```

## オブジェクト
```json:オブジェクトの例
{
  "person1": {
    "name": "Ken",
    "age": 15
  },
  "person2": {
    "name": "Mary",
    "age": 18
  }
}
```

## 配列
```json:配列の例1
[1, 2, 3, 4, 5]
```

```json:配列の例2
["apple", "orange", "grape"]
```

```json:配列の例3
[
  {
    "name": "Ken",
    "age": 15
  },
  {
    "name": "Mary",
    "age": 18
  }
]
```

# JSONとして正しいかをブラウザで確認する方法
step1. 右クリック→「検証」→コンソール
step2. 確認したいJSON文字列をバッククオートで囲む
step3. `JSON.parse()`をする
step4. `typeof`で型を確認する

## 例1
```js
var json = `"hello"`
//=> undefined
JSON.parse(json)
//=> 'hello'
typeof JSON.parse(json)
//=> 'string'
```

## 例2
```js
var json = `1`
//=> undefined
JSON.parse(json)
//=> 1
typeof JSON.parse(json)
//=> 'number'
```

## 例3
```js
var json = `true`
//=> undefined
JSON.parse(json)
//=> true
typeof JSON.parse(json)
//=> 'boolean'
```

## 例4
```js
var json = `null`
//=> undefined
JSON.parse(json)
//=> null
typeof JSON.parse(json)
//=> 'object'
```

> 歴史的な理由で "null" ではありません
引用元： [null - MDN Web Docs](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/null#difference_between_null_and_undefined)


> JavaScript の最初の実装では、JavaScript の値は型タグと値で表現されていました。オブジェクトの型タグは 0 で、null は NULL ポインター (ほとんどのプラットフォームで 0x00) として表されていました。その結果、null はタグの型として 0 を持っていたため、typeof の戻り値は "object" です。
引用元： [typeof null型 - MDN Web Docs](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/typeof#typeof_null)


## 例5

```js
var json = `["true", "false", "true"]`
//=> undefined
JSON.parse(json)
//=> (3) ['true', 'false', 'true']
//=>   0: "true"
//=>   1: "false"
//=>   2: "true"
//=>   length: 3
//=>   [[Prototype]]: Array(0)
typeof JSON.parse(json)
//=> 'object'
typeof JSON.parse(json)[0]
//=> 'string'
```

## 例6

```js
var json = `[true, false, true]`
//=> undefined
JSON.parse(json)
//=> (3) [true, false, true]
//=>   0: true
//=>   1: false
//=>   2: true
//=>   length: 3
//=>   [[Prototype]]: Array(0)
typeof JSON.parse(json)
//=> 'object'
typeof JSON.parse(json)[0]
//=> 'boolean'
```

## 例7

```js
var json = `{
  "person1": {
    "name": "Ken",
    "age": 15
  },
  "person2": {
    "name": "Mary",
    "age": 18
  }
}`
//=> undefined
JSON.parse(json)
//=> {person1: {…}, person2: {…}}
//=>   person1: {name: 'Ken', age: 15}
//=>   person2: {name: 'Mary', age: 18}
//=>   [[Prototype]]: Object
typeof JSON.parse(json)
//=> 'object'
typeof JSON.parse(json).person1
//=> 'object'
```

# 感想
文字列のみ、数値のみでもJSONであることを知りました。
`true`、 `false`、 `null`もJSONのvalueとして使えることを初めて知りました。


# 参考サイト
* [JSON の紹介](https://www.json.org/json-ja.html)
* [JSON データの操作](https://developer.mozilla.org/ja/docs/Learn/JavaScript/Objects/JSON)
* [null - MDN Web Docs](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/null)
* [typeof - MDN Web Docs](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/typeof)