Đổi === thành Object.is có thể làm bộ phát hiện thay đổi xử lý NaN và số 0 khác trước. Tên Object.is cũng dễ khiến người đọc nghĩ đây là cách so sánh nội dung object. Thực tế, cần chọn quy tắc so sánh theo dữ liệu và quyết định nghiệp vụ mà kết quả đó điều khiển.
1. Hai ngoại lệ số học cần biết
console.log(NaN === NaN); // false
console.log(Object.is(NaN, NaN)); // true
console.log(0 === -0); // true
console.log(Object.is(0, -0)); // false
console.log(Object.is('7', 7)); // false
Object.is dùng quy tắc SameValue: nhận hai NaN là cùng giá trị và phân biệt hai dấu của số 0. Nó không chuyển chuỗi thành số trước khi so sánh. Với các giá trị khác, kết quả giống ===. Đối chiếu MDN Object.is và đặc tả SameValue.
Trong một bộ theo dõi dùng !Object.is(previous, next), NaN lặp lại sẽ không được xem là thay đổi. Điều đó không chứng minh phép tính đầu vào hợp lệ: ứng dụng vẫn cần chính sách báo lỗi riêng cho kết quả không phải số hữu hạn.
2. Dấu của số 0 có thể ảnh hưởng phép tính tiếp theo
console.log(1 / 0); // Infinity
console.log(1 / -0); // -Infinity
console.log(String(-0)); // 0
console.log(Object.is(-0, 0)); // false
Hai giá trị có thể cùng được hiển thị thành chữ 0 nhưng tạo kết quả khác khi tính nghịch đảo. Nếu dữ liệu biểu diễn một đại lượng mà hướng tiến về 0 có ý nghĩa, việc tự gộp hai dấu có thể mất thông tin. Nếu đó là số lượng sản phẩm, sản phẩm có thể chủ động quy định hai dạng 0 tương đương.
Đừng dùng ảnh chụp giao diện hoặc chuỗi log đã định dạng làm bằng chứng rằng giá trị số hoàn toàn giống nhau. Khi điều tra lỗi tính toán, kiểm tra giá trị gốc và phép so sánh được dùng tại đúng điểm quyết định cập nhật.
3. Object.is không so sánh sâu và không lưu lịch sử
const reading = { value: 12 };
const previous = reading;
reading.value = 13;
console.log(Object.is(previous, reading)); // true
console.log(previous.value); // 13
console.log(Object.is(reading, { value: 13 })); // false
Cùng tham chiếu vẫn là cùng object sau khi sửa thuộc tính. Biến previous ở đây không phải bản chụp trạng thái cũ. Ngược lại, một object mới có cùng thuộc tính vẫn là tham chiếu khác.
Nếu cần phát hiện thay đổi một trường số, lưu giá trị trường đó trước khi sửa. Nếu cần so sánh toàn bộ bản ghi, xác định danh sách trường, cách xử lý trường thiếu và chính sách cho cấu trúc lồng nhau. Đổi tên hàm so sánh không thay thế việc lưu dữ liệu trước đó.
4. Chọn contract cho số đo hữu hạn
function sameReading(previous, next) {
if (!Number.isFinite(previous) || !Number.isFinite(next)) {
throw new TypeError('readings must be finite numbers');
}
return previous === next;
}
console.log(sameReading(12, 12)); // true
console.log(sameReading(12, 13)); // false
console.log(sameReading(0, -0)); // true
Helper minh họa chính sách: chỉ nhận number hữu hạn, gộp hai dấu 0, yêu cầu bằng nhau chính xác. Chuỗi số, null, NaN và Infinity bị từ chối. Vì đã loại NaN và chủ động gộp số 0, === thể hiện trực tiếp lựa chọn này.
Contract trên không áp dụng sai số cho cảm biến hoặc phép tính dấu phẩy động. Nếu nghiệp vụ cần một ngưỡng chấp nhận, hãy định nghĩa đơn vị và sai số trước, rồi kiểm tra riêng ranh giới ngưỡng đó. Cũng không nên dùng helper để xác thực toàn bộ một bản tin có nhiều trường.
5. Kiểm tra gì trước khi đổi quy tắc so sánh?
- NaN lặp lại là cùng trạng thái lỗi hay phải tạo sự kiện mới?
- Hai dấu của số 0 có ý nghĩa với phép tính kế tiếp không?
- Dữ liệu được lưu là giá trị cũ hay tham chiếu tới object đang bị sửa?
- Cần bằng nhau chính xác hay chấp nhận sai số theo đơn vị nghiệp vụ?
- Đầu vào sai bị từ chối ở đâu trước khi so sánh?
Tám khối mã Việt–Anh đã chạy bằng Node.js, kèm kiểm tra số hữu hạn, kiểu dữ liệu sai và hai dấu số 0. Ví dụ chưa tích hợp hệ thống cảm biến hay giao diện thực tế.




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