JavaScript 中JSON 数据遍历

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)
posted @ 2025-12-01 16:01  冀未然  阅读(9)  评论(0)    收藏  举报