Tại sao `null> = 0 && null <= 0` mà không phải là` null == 0`?


142

Tôi đã phải viết một thói quen làm tăng giá trị của biến lên 1 nếu kiểu của nó là number và gán 0 cho biến nếu không, trong đó biến ban đầu là nullhoặc undefined.

Việc thực hiện đầu tiên là v >= 0 ? v += 1 : v = 0vì tôi nghĩ rằng bất cứ điều gì không phải là một con số sẽ làm cho biểu thức số học trở thành sai, nhưng nó đã sai vì null >= 0được đánh giá là đúng. Sau đó, tôi đã học được các nullhành vi như 0 và các biểu thức sau đây đều được đánh giá là đúng.

  • null >= 0 && null <= 0
  • !(null < 0 || null > 0)
  • null + 1 === 1
  • 1 / null === Infinity
  • Math.pow(42, null) === 1

Tất nhiên, nullkhông phải null == 0là 0. được đánh giá là sai. Điều này làm cho biểu hiện dường như tautological (v >= 0 && v <= 0) === (v == 0)sai.

Tại sao nullgiống như 0, mặc dù nó không thực sự là 0?


3
Anh ấy đang nói về Javascript. Ví dụ của bạn là trong PHP. Trong toán tử PHP == so sánh các giá trị theo một cách đặc biệt. Bạn có thể thực hiện một số so sánh thực sự điên rồ như "10" == "1e1" (đó là sự thật). Nếu bạn đã sử dụng toán tử ===, bạn sẽ nhận được một kết quả hoàn toàn khác vì nó kiểm tra xem loại có khớp với giá trị không. Kiểm tra liên kết này ra: php.net/manual/en/language.operators.comparison.php
Pijusn

Toán tử '==' PHP thực sự hoạt động theo cách "đặc biệt".
Nhà giả kim hai bit

Nếu yêu cầu của bạn là để bắt đầu đếm 1 thay vì 0, có một cách thực sự ngắn gọn đến quầy increment mà ban đầu một trong hai nullhoặc undefined:c = -~c // Results in 1 for null/undefined; increments if already a number
Ates Goral

1
undefinedlà một giá trị biến, cho các biến chưa được khởi tạo. nullmặt khác, là một giá trị đối tượng trống và không được trộn lẫn với các số. nullkhông nên kết hợp với số, vì vậy null không nên hoạt động như số.
Matthew

1
@AtesGoral - ngắn gọn, nhưng không rõ ràng. Đáng để nhắc nhở mọi người rằng bất cứ khi nào làm điều gì đó không rõ ràng, xin vui lòng thêm một nhận xét giải thích những gì mã làm. Trong hầu hết các tình huống, tôi sẽ coi đó là một "tối ưu hóa sớm", với điều kiện là nó đánh đổi sự rõ ràng để đạt được hiệu suất rất nhỏ.
ToolmakerSteve

Câu trả lời:


207

Câu hỏi thực sự của bạn dường như là:

Tại sao:

null >= 0; // true

Nhưng:

null == 0; // false

Điều thực sự xảy ra là Toán tử lớn hơn hoặc bằng ( >=), thực hiện cưỡng chế kiểu ( ToPrimitive), với một loại gợi ýNumber , trên thực tế tất cả các nhà khai thác quan hệ có hành vi này.

nullđược xử lý theo cách đặc biệt bởi Toán tử bằng ( ==). Trong một ngắn gọn, nó chỉ cưỡng ép để undefined:

null == null; // true
null == undefined; // true

Giá trị như false, '', '0', và[] đang phụ thuộc vào số kiểu ép buộc, tất cả trong số họ ép buộc không.

Bạn có thể xem chi tiết bên trong của quá trình này trong Thuật toán so sánh đẳng thức trừu tượngThuật toán so sánh quan hệ trừu tượng .

Tóm tắt:

  • So sánh quan hệ: nếu cả hai giá trị không phải là kiểu String, ToNumberđược gọi trên cả hai. Điều này giống như thêm một +ở phía trước, mà đối với null cưỡng chế 0.

  • So sánh bằng: chỉ gọi các ToNumberchuỗi, số và Booleans.


1
Xin chào CMS, theo lời giải thích của bạn null nguyên thủy là 0, vì vậy 0> = 0 trả về true và == đang trả về false.but theo thuật toán ecma Nếu Loại (x) là Đối tượng và Loại (y) là Chuỗi hoặc Số, trả về kết quả so sánh ToPrimitive (x) == y.then trong trường hợp này sẽ trả về true. Xin vui lòng giải thích cho tôi
bharath muppa

cho tôi câu trả lời không cung cấp một câu trả lời - null is treated in a special way by the Equals Operator (==). In a brief, it only coerces to undefined:- và những gì? Bạn có thể giải thích, tại sao null >= 0? :)
Andrey Deineko

@bharathmuppa @ andrey-deineko: Phần còn lại của câu trả lời của CMS là ở đây: Thuật toán so sánh quan hệ trừu tượng giải thích ở điểm 3. rằng nếu cả hai giá trị không phải là String, ToNumber được gọi trên cả hai. Điều này giống như thêm một +ở phía trước, mà đối với null cưỡng chế 0. Equality chỉ gọi ToNumber trên Chuỗi, Số và Booleans.
Michael Liquori

7
Mô tả tốt, nhưng tôi không thích nó. Trong bất kỳ ngôn ngữ nào (x == 0 || x> 0) phải tương đương với (x> = 0). javascript là một ngôn ngữ ngu ngốc.
John Henckel

1
Nó thực sự chỉ là một lỗi trong thông số kỹ thuật (vì về mặt toán học là sai) và không có gì để làm vì nó hàng triệu trang web dựa trên so sánh null ^^ '
mahieddine

14

Tôi muốn mở rộng câu hỏi để cải thiện hơn nữa khả năng hiển thị của vấn đề:

null >= 0; //true
null <= 0; //true
null == 0; //false
null > 0;  //false
null < 0;  //false

Nó chỉ làm cho không có ý nghĩa. Giống như ngôn ngữ của con người, những điều này cần phải được học thuộc lòng.


1
Như được mô tả ở trên, nó có thể được giải thích chỉ bằng một ngoại lệ như cách == xử lý null, nếu không, trong mọi trường hợp, null được chuyển thành 0 bằng cách sử dụng Số (nulll)
Sourabh Ranka

5

JavaScript có cả so sánh chuyển đổi nghiêm ngặt và kiểu loại

null >= 0;đúng nhưng (null==0)||(null>0)sai

null <= 0;đúng nhưng (null==0)||(null<0)sai

"" >= 0 cũng đúng

Đối với các phép so sánh trừu tượng quan hệ (<=,> =), các toán hạng trước tiên được chuyển đổi thành nguyên hàm, sau đó thành cùng loại, trước khi so sánh.

typeof null returns "object"

Khi loại là đối tượng, javascript cố gắng xâu chuỗi đối tượng (tức là null), các bước sau đây được thực hiện ( ECMAScript 2015 ):

  1. Nếu PreferredTypekhông được thông qua, hãy để hint"mặc định".
  2. Khác nếu PreferredTypehintChuỗi, hãy hintlà "chuỗi".
  3. Khác PreferredTypehintsố, hãy hintlà "số".
  4. Hãy để exoticToPrimGetMethod(input, @@toPrimitive).
  5. ReturnIfAbrupt(exoticToPrim).
  6. Nếu exoticToPrimkhông được xác định, thì
    a) Đặt kết quả là Call(exoticToPrim, input, «hint»).
    b) ReturnIfAbrupt(result).
    c) Nếu Type(result)không phải là Object, trả về kết quả.
    d) Ném ngoại lệ TypeError.
  7. Nếu hintlà "mặc định", hãy hintlà "số".
  8. Quay trở lại OrdinaryToPrimitive(input,hint).

Các giá trị được phép cho gợi ý là "mặc định", "số" và "chuỗi". Các đối tượng ngày, là duy nhất trong số các đối tượng ECMAScript tích hợp ở chỗ chúng coi "mặc định" là tương đương với "chuỗi". Tất cả các đối tượng ECMAScript tích hợp khác coi "mặc định" là tương đương với "số" . ( Bản thảo 20.3.4.45 )

Vì vậy, tôi nghĩ nullchuyển đổi thành 0.


1

Tôi đã từng gặp vấn đề tương tự !!. Hiện tại giải pháp duy nhất của tôi là tách ra.

var a = null;
var b = undefined;

if (a===0||a>0){ } //return false  !work!
if (b===0||b>0){ } //return false  !work!

//but 
if (a>=0){ } //return true !

Nó có thể rõ ràng hơn để thay thế : if (a!=null && a>=0). Điều này làm rõ lý do không chỉ đơn giản là tự làm >=: "a có thể là null (hoặc không xác định, cũng là '== null')".
ToolmakerSteve

0
console.log( null > 0 );  // (1) false
console.log( null == 0 ); // (2) false
console.log( null >= 0 ); // (3) true

Về mặt toán học, điều đó thật lạ. Kết quả cuối cùng nói rằng "null lớn hơn hoặc bằng 0", do đó, trong một trong những so sánh ở trên, nó phải đúng, nhưng cả hai đều sai.

Lý do là một kiểm tra bình đẳng ==và so sánh > < >= <=hoạt động khác nhau. So sánh chuyển đổi null thành một số, coi nó là 0. Đó là lý do tại sao (3) null >= 0truevà (1) null > 0false.

Mặt khác, việc kiểm tra bình đẳng ==cho undefinednullđược định nghĩa như vậy mà, mà không cần bất kỳ chuyển đổi, họ tương đương với nhau và làm bất cứ điều gì không bình đẳng khác. Đó là lý do tại sao (2) null == 0false.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.