JavaScriptにおけるJSONの基礎

2025-07-28

JSONとは

JSON(JavaScript Object Notation)は、軽量なデータ交換フォーマットです。JavaScriptのオブジェクト表記法に基づいていますが、独立したデータ形式として多くのプログラミング言語でサポートされています。

JSONの特徴

  • テキストベース:人間が読める形式
  • 軽量:XMLなどに比べてデータサイズが小さい
  • 言語非依存:多くのプログラミング言語で扱える
  • JavaScriptと親和性が高い:簡単に相互変換可能

JSONの基本構造

有効なJSONデータ型

  1. 文字列" "で囲む
   "Hello, World!"
  1. 数値:整数または浮動小数点数
   42
   3.14159
  1. 真偽値
   true
   false
  1. null
   null
  1. 配列[]で囲む
   [1, 2, 3, "four", true]
  1. オブジェクト{}で囲み、"key": valueのペアで構成
   {
     "name": "山田太郎",
     "age": 30,
     "isStudent": false
   }

無効なJSON表現

  • 関数やundefinedは使用不可
  • コメントはサポートされていない
  • キーは必ずダブルクォートで囲む必要がある
  • 末尾のカンマが許されない

JavaScriptでのJSON操作

JSON文字列 ⇄ JavaScriptオブジェクトの変換

JSON.parse() – 文字列からオブジェクトへ

const jsonString = '{"name":"山田太郎","age":30}';
const obj = JSON.parse(jsonString);
console.log(obj.name); // "山田太郎"

JSON.stringify() – オブジェクトから文字列へ

const user = {
  name: "山田太郎",
  age: 30,
  hobbies: ["読書", "プログラミング"]
};

const jsonString = JSON.stringify(user);
console.log(jsonString); 
// '{"name":"山田太郎","age":30,"hobbies":["読書","プログラミング"]}'

オプションパラメータ

JSON.stringify()の第2引数(リプレーサー)

// 特定のプロパティのみ含める
const json = JSON.stringify(user, ["name", "age"]);
console.log(json); // '{"name":"山田太郎","age":30}'

// 関数で変換を制御
const json = JSON.stringify(user, (key, value) => {
  if (key === "age") return undefined; // ageプロパティを除外
  return value;
});

第3引数(スペース数)

// 整形出力(人間が読みやすい形式)
const prettyJson = JSON.stringify(user, null, 2);
console.log(prettyJson);
/*
{
  "name": "山田太郎",
  "age": 30,
  "hobbies": [
    "読書",
    "プログラミング"
  ]
}
*/

カスタムtoJSONメソッド

const person = {
  name: "山田太郎",
  age: 30,
  toJSON() {
    return {
      fullName: this.name,
      years: this.age
    };
  }
};

console.log(JSON.stringify(person)); 
// '{"fullName":"山田太郎","years":30}'

JSONの実践的な使用例

API通信でのJSON

// APIからデータ取得
fetch('https://api.example.com/users')
  .then(response => response.json()) // JSONをパース
  .then(data => console.log(data))
  .catch(error => console.error(error));

// データ送信
const newUser = { name: "花子", age: 25 };
fetch('https://api.example.com/users', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(newUser)
});

ローカルストレージでの利用

// 保存
const settings = { theme: "dark", fontSize: 14 };
localStorage.setItem('userSettings', JSON.stringify(settings));

// 読み取り
const savedSettings = JSON.parse(localStorage.getItem('userSettings'));
console.log(savedSettings.theme); // "dark"

設定ファイルとしてのJSON

// config.json
{
  "apiUrl": "https://api.example.com",
  "maxRetries": 3,
  "timeout": 5000
}

// JavaScriptで読み込み
fetch('config.json')
  .then(response => response.json())
  .then(config => {
    console.log(`API URL: ${config.apiUrl}`);
  });

JSON Schemaによる検証

JSONデータの構造を定義・検証する仕様です。

// person.schema.json
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    "name": { "type": "string" },
    "age": { "type": "number", "minimum": 0 }
  },
  "required": ["name"]
}

セキュリティ上の注意点

  1. JSONインジェクションeval()を使用しない
   // 危険な例
   const obj = eval('(' + jsonString + ')');

   // 安全な例
   const obj = JSON.parse(jsonString);
  1. 巨大JSONの処理:ストリーミング処理を検討

stream-json というライブラリを使った安全なJSONストリーミング解析例

    const fs = require('fs');
    const { parser } = require('stream-json');
    const { streamArray } = require('stream-json/streamers/StreamArray');

    const jsonStream = fs.createReadStream('huge.json')
        .pipe(parser())
        .pipe(streamArray());

    jsonStream.on('data', ({ key, value }) => {
        // 要素ごとに安全に処理できる
        console.log(`Key: ${key}, Value:`, value);
    });

    jsonStream.on('end', () => {
        console.log('JSON parsing complete.');
    });
  1. 循環参照JSON.stringify()でエラーが発生

オブジェクト内で自分自身を参照している(または互いに参照し合っている)と、JSON.stringify() はエラーになります。

   const obj = { a: 1 };
   obj.self = obj;
   JSON.stringify(obj); // TypeError

パフォーマンス最適化

  1. 大きなJSON:分割処理やストリーミングを検討
  2. 頻繁な操作:一度パースしてキャッシュ
  3. Web Worker:メインスレッドをブロックしない

演習問題

初級問題(3問)

  1. 次のJavaScriptオブジェクトをJSON文字列に変換しなさい。
   const book = {
     title: "JavaScript入門",
     price: 2500,
     inStock: true
   };
  1. 次のJSON文字列をJavaScriptオブジェクトに変換し、authorプロパティにアクセスしなさい。
   {
     "title": "JSONガイド",
     "author": "山田太郎",
     "published": false
   }
  1. 次のJSONのどこが間違っているか指摘しなさい。
   {
     name: "エラー例",
     "values": [1, 2, 3],
     "active": true,
   }

中級問題(6問)

  1. 次のオブジェクトをJSONに変換する際、passwordプロパティが含まれないようにしなさい。
   const user = {
     username: "js_user",
     password: "secret123",
     email: "user@example.com"
   };
  1. 次のJSON配列から、ageが30以上の人のnameだけを含む配列を作成しなさい。
   [
     { "name": "太郎", "age": 25 },
     { "name": "花子", "age": 30 },
     { "name": "次郎", "age": 35 }
   ]
  1. 深い階層を持つ次のJSONから、streetの値を取得しなさい。
   {
     "user": {
       "name": "山田太郎",
       "address": {
         "city": "東京",
         "street": "渋谷区1-2-3"
       }
     }
   }
  1. 次の2つのJSONオブジェクトをマージしなさい(競合時はobj2の値が優先される)。
   const obj1 = { "a": 1, "b": 2 };
   const obj2 = { "b": 3, "c": 4 };
  1. 次のJSON文字列を整形(インデント2スペース)してコンソールに出力しなさい。
   {"name":"整形例","values":[1,2,3],"active":true}
  1. 次のコードの出力結果とその理由を説明しなさい。
   const obj = { date: new Date() };
   console.log(JSON.stringify(obj));

上級問題(3問)

  1. 次のような循環参照を持つオブジェクトをJSON文字列に変換するカスタム関数を作成しなさい(循環参照は"[Circular]"という文字列に変換)。
const obj = { a: 1 }; 
obj.self = obj;
  1. 巨大なJSONファイルをストリーミング処理するNode.jsのコード例を書きなさい(ファイルから読み取り、パースしながら処理)。
  1. JSON Schemaを使用して、次の要件を満たすスキーマを定義しなさい。
  • オブジェクト型
  • 必須プロパティ: id(数値), name(文字列)
  • オプションプロパティ: tags(文字列の配列、最大5個まで)
  • idは正の整数

解答例

初級問題解答

  1. JSON文字列に変換
   const jsonString = JSON.stringify(book);
   // '{"title":"JavaScript入門","price":2500,"inStock":true}'
  1. JSONをオブジェクトに変換
   const jsonObj = JSON.parse('{"title":"JSONガイド","author":"山田太郎","published":false}');
   console.log(jsonObj.author); // "山田太郎"
  1. JSONの間違い
  • nameがダブルクォートで囲まれていない
  • 最後のプロパティに余分なカンマがある
    {
        "name": "エラー例",     // nameもダブルクウォートで囲む
        "values": [1, 2, 3],
        "active": true        // 最後のプロパティはカンマなし   
    }

中級問題解答

  1. passwordを除外
   const json = JSON.stringify(user, (key, val) => 
     key === "password" ? undefined : val
   );
  1. ageが30以上の人のnameだけを含む配列
   const people = JSON.parse('[{"name":"太郎","age":25},{"name":"花子","age":30},{"name":"次郎","age":35}]');
   const names = people.filter(p => p.age >= 30).map(p => p.name);
  1. streetの値を取得
   const data = JSON.parse('{"user":{"name":"山田太郎","address":{"city":"東京","street":"渋谷区1-2-3"}}}');
   const street = data.user.address.street;
  1. オブジェクトのマージ
   const merged = JSON.stringify({ ...obj1, ...obj2 });
   // '{"a":1,"b":3,"c":4}'
  1. JSON文字列を整形(インデント2スペース)してコンソールに出力
   const jsonObj = JSON.parse('{"name":"整形例","values":[1,2,3],"active":true}');
   console.log(JSON.stringify(jsonObj, null, 2));
  1. 出力結果とその理由を説明

{“date”:”2023-05-01T00:00:00.000Z”}

    const obj = { date: new Date() };
    console.log(JSON.stringify(obj));   // {"date":"2023-10-01T00:00:00.000Z"}
                                        // DateオブジェクトはJSON.stringify()で文字列に変換される

上級問題解答

  1. 循環参照を処理する関数
function safeStringify(obj) { 
    const seen = new WeakSet(); 
    return JSON.stringify(obj, (key, value) => { 
        if (typeof value === "object" && value !== null) { 
            if (seen.has(value)) return "[Circular]"; 
            seen.add(value); 
        } 
        return value; 
    }); 
}
  1. ストリーミング処理の例(Node.js)
const fs = require('fs'); 
const { parse } = require('JSONStream'); 
const stream = fs.createReadStream('large.json') .pipe(parse('*')); 
stream.on('data', data => { // データを逐次処理 console.log(data); });
  1. JSON Schemaの例
json { 
    "$schema": "http://json-schema.org/draft-07/schema#", 
    "type": "object", 
    "properties": { 
        "id": { 
            "type": "integer", 
            "minimum": 1 
        }, 
        "name": { 
            "type": "string" 
        }, 
        "tags": { 
            "type": "array", 
            "items": { 
                "type": "string" 
            }, 
            "maxItems": 5
        } 
    }, 
    "required": ["id", "name"] 
}