JavaScript 中JSON 數據遍歷

1. JSON 字符串轉對象後遍歷

1.1 解析 JSON 字符串

const jsonString = '{"users": [{"id": 1, "name": "張三"}, {"id": 2, "name": "李四"}]}';
const data = JSON.parse(jsonString);

// 遍歷數組
data.users.forEach(user => {
    console.log(`ID: ${user.id}, 姓名: ${user.name}`);
});

// 1.2 從 API 獲取的 JSON
fetch('/api/user/realname/王')
    .then(response => response.json())
    .then(data => {
        // 遍歷返回的 JSON 數據
        if (Array.isArray(data)) {
            data.forEach(user => {
                console.log(user.realname, user.email);
            });
        }
    });

2. 遍歷 JSON 對象(Object)

const user = {
    "id": 1,
    "username": "zhangsan",
    "realname": "張三",
    "email": "zhangsan@example.com",
    "department": {
        "id": 101,
        "name": "技術部"
    }
};

// 2.1 Object.keys() + forEach
Object.keys(user).forEach(key => {
    console.log(`${key}: ${user[key]}`);
});

// 2.2 for...in 循環(會遍歷原型鏈屬性)
for (const key in user) {
    if (user.hasOwnProperty(key)) {
        console.log(`${key}: ${user[key]}`);
    }
}

// 2.3 Object.entries() - 獲取鍵值對數組
Object.entries(user).forEach(([key, value]) => {
    console.log(`${key}: ${JSON.stringify(value)}`);
});

// 2.4 Object.values() - 只獲取值
Object.values(user).forEach(value => {
    console.log(value);
});

3. 遍歷嵌套的 JSON 數據

const company = {
    "companyName": "ABC公司",
    "departments": [
        {
            "id": 1,
            "name": "技術部",
            "employees": [
                {"id": 101, "name": "張三", "role": "前端開發"},
                {"id": 102, "name": "李四", "role": "後端開發"}
            ]
        },
        {
            "id": 2,
            "name": "市場部",
            "employees": [
                {"id": 201, "name": "王五", "role": "市場專員"},
                {"id": 202, "name": "李莉", "role": "價格管理"},
                {"id": 203, "name": "張琪", "role": "檔案管理"},
                {"id": 204, "name": "郝錚", "role": "綜合管理"}
            ]
        }
    ]
};

// 3.1 多層嵌套遍歷
company.departments.forEach(dept => {
    console.log(`部門: ${dept.name}`);
    dept.employees.forEach(emp => {
        console.log(`  - ${emp.name} (${emp.role})`);
    });
});

// 3.2 遞歸遍歷所有屬性
function traverseJSON(obj, depth = 0) {
    const indent = '  '.repeat(depth);
    
    if (Array.isArray(obj)) {
        obj.forEach(item => traverseJSON(item, depth + 1));
    } else if (obj !== null && typeof obj === 'object') {
        Object.entries(obj).forEach(([key, value]) => {
            if (typeof value === 'object') {
                console.log(`${indent}${key}:`);
                traverseJSON(value, depth + 1);
            } else {
                console.log(`${indent}${key}: ${value}`);
            }
        });
    } else {
        console.log(`${indent}${obj}`);
    }
}

traverseJSON(company);

4. 處理從 API 返回的 JSON 數據

// 假設 API 返回:{ "success": true, "data": [{...}, {...}], "total": 2 }

async function fetchAndProcessUsers() {
    try {
        const response = await fetch('/api/users');
        const result = await response.json();
        
        // 4.1 檢查 API 返回狀態
        if (!result.success) {
            throw new Error(result.message || '請求失敗');
        }
        
        // 4.2 遍歷數據
        const users = result.data;
        
        // 方式1: 簡單遍歷
        users.forEach((user, index) => {
            console.log(`用户${index + 1}:`, user);
        });
        
        // 方式2: 使用 map 轉換數據
        const userNames = users.map(user => ({
            id: user.id,
            displayName: `${user.realname} (${user.username})`,
            department: user.deptname
        }));
        
        // 方式3: 使用 filter 篩選
        const activeUsers = users.filter(user => 
            user.status === 'active' && user.deptname === '技術部'
        );
        
        // 方式4: 使用 reduce 統計
        const departmentCount = users.reduce((acc, user) => {
            acc[user.deptname] = (acc[user.deptname] || 0) + 1;
            return acc;
        }, {});
        
        console.log('部門統計:', departmentCount);
        
        return userNames;
        
    } catch (error) {
        console.error('處理數據失敗:', error);
    }
}

5. 將遍歷結果轉為 HTML

async function displayUsersInTable() {
    const response = await fetch('/api/user/realname/王');
    const users = await response.json();
    
    const tableBody = document.querySelector('#userTable tbody');
    tableBody.innerHTML = ''; // 清空現有內容
    
    // 遍歷 JSON 數據生成表格行
    users.forEach(user => {
        const row = document.createElement('tr');
        
        // 創建單元格
        const cells = [
            user.id,
            user.realname,
            user.username,
            user.deptname,
            user.mobile,
            user.email
        ];
        
        cells.forEach(cellData => {
            const cell = document.createElement('td');
            cell.textContent = cellData || 'N/A';
            row.appendChild(cell);
        });
        
        // 添加操作按鈕
        const actionCell = document.createElement('td');
        actionCell.innerHTML = `
            <button onclick="editUser(${user.id})">編輯</button>
            <button onclick="deleteUser(${user.id})">刪除</button>
        `;
        row.appendChild(actionCell);
        
        tableBody.appendChild(row);
    });
}

使用模板字符串

function displayUsersWithTemplate(users) {
    const container = document.getElementById('userContainer');
    
    const userCards = users.map(user => `
        <div class="user-card">
            <h3>${escapeHtml(user.realname)}</h3>
            <p><strong>用户名:</strong> ${escapeHtml(user.username)}</p>
            <p><strong>部門:</strong> ${escapeHtml(user.deptname || '未分配')}</p>
            <p><strong>手機:</strong> ${escapeHtml(user.mobile || 'N/A')}</p>
            <p><strong>郵箱:</strong> ${escapeHtml(user.email || 'N/A')}</p>
            <button class="btn-view" data-id="${user.id}">查看詳情</button>
        </div>
    `).join('');
    
    container.innerHTML = userCards;
    
    // 添加事件監聽
    container.querySelectorAll('.btn-view').forEach(button => {
        button.addEventListener('click', (e) => {
            const userId = e.target.dataset.id;
            viewUserDetail(userId);
        });
    });
}

防止 XSS 攻擊的簡單轉義函數

function escapeHtml(text) {
    const div = document.createElement('div');
    div.textContent = text;
    return div.innerHTML;
}

6. 使用現代 JavaScript 特性

6.1 使用可選鏈和空值合併

users?.forEach(user => {
    const email = user.email ?? '暫無郵箱';
    const dept = user.department?.name ?? '未分配部門';
    console.log(`${user.realname} - ${dept} - ${email}`);
});

6.2 使用解構賦值

users.forEach(({ id, realname: name, email = '無郵箱' }) => {
    console.log(`ID: ${id}, 姓名: ${name}, 郵箱: ${email}`);
});

6.3 使用 flatMap 處理嵌套數組

const allEmployees = companyData.departments.flatMap(dept => 
    dept.employees.map(emp => ({
        ...emp,
        department: dept.name
    }))
);

6.4 使用 Set 去重

const uniqueDepartments = [...new Set(users.map(user => user.deptname))];

7. 處理大型 JSON 數據的技巧

7.1 分塊處理(避免阻塞主線程)

async function processLargeDataset(users) {
    const chunkSize = 100;
    
    for (let i = 0; i < users.length; i += chunkSize) {
        const chunk = users.slice(i, i + chunkSize);
        
        // 處理當前塊
        chunk.forEach(user => {
            // 處理邏輯
        });
        
        // 讓出主線程,避免阻塞
        await new Promise(resolve => setTimeout(resolve, 0));
    }
}

7.2 使用 Web Worker 處理大型 JSON

const worker = new Worker('json-processor.js');
worker.postMessage({ users: largeJsonData });
worker.onmessage = (e) => {
    console.log('處理結果:', e.data);
};

// json-processor.js
self.onmessage = (e) => {
    const users = e.data.users;
    const processed = users.map(user => {
        // 在 Worker 線程中處理
        return { ...user, processed: true };
    });
    self.postMessage(processed);
};

8. 錯誤處理和驗證

async function safeJsonTraversal(url) {
    try {
        const response = await fetch(url);
        
        // 驗證響應
        if (!response.ok) {
            throw new Error(`HTTP錯誤: ${response.status}`);
        }
        
        // 解析 JSON
        const data = await response.json();
        
        // 驗證數據結構
        if (!data || typeof data !== 'object') {
            throw new Error('無效的JSON格式');
        }
        
        // 安全遍歷
        if (Array.isArray(data)) {
            return data.map(item => ({
                ...item,
                // 確保必要字段存在
                id: item.id || 0,
                realname: item.realname || '未知用户'
            }));
        }
        
        return data;
        
    } catch (error) {
        console.error('JSON處理失敗:', error);
        return null;
    }
}

總結

場景

推薦方法

示例

遍歷數組

forEach(), for...of

users.forEach(user => {...})

轉換數組

map()

users.map(u => u.name)

篩選數組

filter()

users.filter(u => u.active)

遍歷對象

Object.entries()

Object.entries(obj)

獲取鍵

Object.keys()

Object.keys(obj)

獲取值

Object.values()

Object.values(obj)

關鍵點:

  1. 先確定 JSON 數據的結構(數組還是對象)
  2. 使用合適的遍歷方法
  3. 注意錯誤處理和空值檢查
  4. 對於複雜嵌套,考慮使用遞歸
  5. 處理用户輸入時注意安全(防 XSS)