Là một nhà toán học chuyên nghiệp, tôi thấy trong toán tử mẫu của Javscript ==
(còn gọi là "so sánh trừu tượng", "bình đẳng lỏng lẻo" ) một nỗ lực xây dựng mối quan hệ tương đương giữa các thực thể, bao gồm tính phản xạ , đối xứng và bắc cầu . Thật không may, hai trong số ba thuộc tính cơ bản này thất bại:
==
không phải là phản xạ :
A == A
có thể sai, vd
NaN == NaN // false
==
không mang tính bắc cầu :
A == B
và B == C
cùng nhau không ngụ ý A == C
, ví dụ
'1' == 1 // true
1 == '01' // true
'1' == '01' // false
Chỉ có tài sản đối xứng tồn tại:
A == B
ngụ ý B == A
, vi phạm có lẽ là không thể tưởng tượng trong mọi trường hợp và sẽ dẫn đến nổi loạn nghiêm trọng;)
Tại sao quan hệ tương đương có vấn đề?
Bởi vì đó là loại quan hệ phổ biến và phổ biến nhất, được hỗ trợ bởi nhiều ví dụ và ứng dụng. Ứng dụng quan trọng nhất là phân rã các thực thể thành các lớp tương đương , bản thân nó là một cách hiểu rất thuận tiện và trực quan để hiểu các mối quan hệ. Và việc không tương đương dẫn đến việc thiếu các lớp tương đương, điều này dẫn đến việc thiếu trực giác và sự phức tạp không cần thiết được biết đến.
Tại sao nó là một ý tưởng khủng khiếp để viết ==
cho một mối quan hệ không tương đương?
Bởi vì nó phá vỡ sự quen thuộc và trực giác của chúng tôi, vì theo nghĩa đen, bất kỳ mối quan hệ thú vị nào về sự tương đồng, bình đẳng, đồng đẳng, đẳng cấu, bản sắc, v.v ... là một sự tương đương.
Chuyển đổi loại
Thay vì dựa vào sự tương đương trực quan, JavaScript giới thiệu chuyển đổi loại:
Toán tử đẳng thức chuyển đổi các toán hạng nếu chúng không cùng loại, sau đó áp dụng so sánh nghiêm ngặt.
Nhưng chuyển đổi loại được định nghĩa như thế nào? Thông qua một bộ quy tắc phức tạp với nhiều ngoại lệ?
Cố gắng xây dựng mối quan hệ tương đương
Booleans. Rõ ràng true
và false
không giống nhau và nên ở trong các lớp khác nhau.
Số. May mắn thay, sự bằng nhau của các số đã được xác định rõ, trong đó hai số khác nhau không bao giờ trong cùng một lớp tương đương. Trong toán học, đó là. Trong JavaScript, khái niệm số có phần bị biến dạng thông qua sự hiện diện của kỳ lạ hơn -0
, Infinity
và -Infinity
. Trực giác toán học của chúng tôi chỉ ra rằng 0
và -0
nên ở trong cùng một lớp (thực tế -0 === 0
là vậy true
), trong khi mỗi trường hợp là một lớp riêng biệt.
Số và Booleans. Cho các lớp số, chúng ta đặt booleans ở đâu? false
trở nên tương tự 0
, trong khi true
trở nên tương tự 1
nhưng không có số khác:
true == 1 // true
true == 2 // false
Có logic nào ở đây để đặt true
cùng với 1
? Phải thừa nhận 1
là khác biệt, nhưng cũng vậy -1
. Cá nhân tôi không thấy bất kỳ lý do để chuyển đổi true
sang 1
.
Và nó thậm chí còn tồi tệ hơn:
true + 2 // 3
true - 1 // 0
Vì vậy, true
thực sự được chuyển đổi thành 1
một trong số tất cả các số! Nó có logic không? Có trực quan không? Câu trả lời còn lại là bài tập;)
Nhưng những gì về điều này:
1 && true // true
2 && true // true
Boolean chỉ x
có x && true
con người true
là x = true
. Điều đó chứng tỏ rằng cả hai 1
và 2
(và bất kỳ số nào khác ngoài 0
) chuyển đổi thành true
! Những gì nó thấy là chuyển đổi của chúng tôi không khác tính chất quan trọng - là song ánh . Có nghĩa là hai thực thể khác nhau có thể chuyển đổi thành cùng một. Mà, tự nó, không phải là một vấn đề lớn. Vấn đề lớn nảy sinh khi chúng tôi sử dụng chuyển đổi này để mô tả mối quan hệ "giống nhau" hoặc "bình đẳng lỏng lẻo" của bất cứ điều gì chúng tôi muốn gọi nó. Nhưng có một điều rõ ràng - nó sẽ không phải là một mối quan hệ tương đương và nó sẽ không được mô tả bằng trực giác thông qua các lớp tương đương.
Nhưng chúng ta có thể làm tốt hơn không?
Ít nhất là về mặt toán học - chắc chắn là có! Một mối quan hệ tương đương đơn giản giữa booleans và số có thể được xây dựng chỉ với false
và 0
nằm trong cùng một lớp. Vì vậy, false == 0
sẽ là bình đẳng lỏng lẻo không tầm thường.
Còn dây thì sao?
Chúng ta có thể cắt các chuỗi từ khoảng trắng ở đầu và cuối để chuyển đổi thành số, ngoài ra chúng ta có thể bỏ qua các số 0 ở phía trước:
' 000 ' == 0 // true
' 0010 ' == 10 // true
Vì vậy, chúng ta có một quy tắc đơn giản cho một chuỗi - cắt bớt các khoảng trắng và số 0 ở phía trước. Hoặc là chúng tôi nhận được một số hoặc chuỗi trống, trong trường hợp đó chúng tôi chuyển đổi thành số đó hoặc bằng không. Hoặc chúng tôi không nhận được một số, trong trường hợp đó chúng tôi không chuyển đổi và do đó không có mối quan hệ mới.
Bằng cách này, chúng tôi thực sự có thể có được một mối quan hệ tương đương hoàn hảo trên tổng số booleans, số và chuỗi! Ngoại trừ việc ... các nhà thiết kế JavaScript rõ ràng có ý kiến khác:
' ' == '' // false
Vì vậy, hai chuỗi mà cả hai chuyển đổi thành 0
đột nhiên không giống nhau! Tại sao hay tại sao? Theo quy tắc, các chuỗi là lỏng lẻo chính xác khi chúng hoàn toàn bằng nhau! Không chỉ quy tắc này phá vỡ tính siêu việt như chúng ta thấy, mà còn là dư thừa! Điểm tạo ra một toán tử khác ==
để làm cho nó hoàn toàn giống với toán tử kia là ===
gì?
Phần kết luận
Toán tử đẳng thức lỏng lẻo ==
có thể rất hữu ích nếu nó tuân theo một số định luật toán học cơ bản. Nhưng thật đáng buồn là nó không hữu dụng.