Lập trình · 23/10/2026

Object.is trong JavaScript: vì sao NaN bằng chính nó nhưng +0 khác -0?

Đổ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.

Object.is trong JavaScript: vì sao NaN bằng chính nó nhưng +0 khác -0?

Đổ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ế.

Thảo luận

Bình luận 0

Đăng nhập để bình luận

Bạn cần có tài khoản để tham gia thảo luận và trả lời độc giả khác.

Đăng nhậpĐăng ký

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