JSON hợp lệ nhưng JSON.parse trả về undefined sau khi thêm callback để kiểm tra dữ liệu. Tham số reviver là một bước biến đổi, không phải callback chỉ để quan sát. Giá trị trả về của nó quyết định giữ, thay thế hay xóa từng phần của kết quả.
1. Callback không return có thể xóa cả kết quả
const visited = [];
const result = JSON.parse('{"count":2}', (key, value) => {
visited.push(key);
});
console.log(result === undefined); // true
console.log(JSON.stringify(visited)); // ["count",""]
Callback trả undefined khi không có return. Reviver xử lý thuộc tính count rồi tới giá trị gốc với khóa rỗng. Vì callback cũng trả undefined ở lượt gốc, toàn bộ kết quả parse trở thành undefined. Đây không phải SyntaxError của JSON.
2. Trả lại value cho những trường cần giữ
const result = JSON.parse('{"label":"ready","enabled":false}', (key, value) => {
if (key === 'label' && typeof value === 'string') {
return value.toUpperCase();
}
return value;
});
console.log(JSON.stringify(result)); // {"label":"READY","enabled":false}
Nhánh mặc định return value giữ nguyên những phần không cần biến đổi, gồm cả object gốc. Không dùng return value || undefined để “bỏ giá trị trống”: cách đó còn xóa false, 0 và chuỗi rỗng dù chúng có thể hợp lệ.
Quy tắc theo tên label sẽ áp dụng ở mọi tầng có cùng tên. Nếu chỉ một đường dẫn cụ thể được phép thay đổi, cân nhắc parse trước rồi biến đổi theo schema rõ ràng thay vì lọc tên trường toàn cục.
3. Xóa phần tử mảng để lại ô trống
const result = JSON.parse('[1,2,3]', (key, value) => {
if (value === 2) return undefined;
return value;
});
console.log(result.length); // 3
console.log(Object.hasOwn(result, 1)); // false
console.log(JSON.stringify(result)); // [1,null,3]
Ví dụ tự kiểm chứng rằng mảng vẫn dài 3 và vị trí 1 không còn thuộc tính riêng. Khi xuất lại JSON, ô trống được biểu diễn thành null. Điều này không có nghĩa reviver đã thay số 2 bằng null trong bộ nhớ.
Nếu mục tiêu là danh sách ngắn hơn, parse rồi dùng bước lọc có chủ đích. Cần chọn rõ loại bỏ theo giá trị, theo chỉ mục hay theo thuộc tính bản ghi; không dùng việc trả undefined như một phép dồn mảng.
4. Con được xử lý trước cha
const order = [];
const result = JSON.parse('{"child":{"value":2}}', (key, value) => {
order.push(key);
if (key === 'value') return value * 10;
if (key === 'child') console.log(value.value); // 20
return value;
});
console.log(JSON.stringify(order)); // ["value","child",""]
console.log(result.child.value); // 20
Reviver ở child nhận object đã chứa giá trị biến đổi của con. Lượt cuối xử lý gốc dùng khóa ''. Tuy nhiên, JSON cũng có thể chứa một thuộc tính thật với tên rỗng, nên chỉ dựa vào key === '' không phải cách nhận diện gốc an toàn cho mọi dữ liệu tùy ý.
JSON.parse không tự xác nhận schema ứng dụng. Sau biến đổi, vẫn cần kiểm tra các trường bắt buộc, kiểu và miền giá trị. Các ví dụ trong bài chỉ dùng JSON nhỏ, không xử lý ngày tháng hoặc định dạng số đặc biệt.
5. Checklist khi thêm reviver
- Mỗi nhánh cần giữ dữ liệu phải trả value.
- Kiểm tra giá trị gốc trả về, không chỉ thuộc tính con.
- Thử false, 0, chuỗi rỗng và null.
- Thử mảng và kiểm tra cả length lẫn ô trống.
- Xác định quy tắc có áp dụng cho trường cùng tên ở tầng khác không.
- Kiểm tra schema sau biến đổi.
Tám khối ví dụ Việt–Anh đã chạy bằng Node.js, kèm kiểm tra giữ giá trị falsy và lượt xử lý gốc. Chưa kiểm thử tích hợp API hoặc hiệu năng. Tham khảo MDN JSON.parse và đặc tả ECMAScript JSON.parse.




Chưa có bình luận. Hãy là người đầu tiên chia sẻ ý kiến.