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) |
关键点:
- 先确定 JSON 数据的结构(数组还是对象)
- 使用合适的遍历方法
- 注意错误处理和空值检查
- 对于复杂嵌套,考虑使用递归
- 处理用户输入时注意安全(防 XSS)