📜 ⬆️ ⬇️

JavaScript: the mysterious case of the expression null> = 0



Once I collected materials to arrange a jigsaw program on JavaScript for a couple of colleagues. Then I came across a rather interesting example in which the comparison of null value with zero was considered. As a matter of fact, here is an example:

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

At first glance - a complete nonsense. How can a certain value be no greater than 0, not equal to zero, but at the same time be greater or equal to zero ?


Although at first I left it without much attention, having decided that the whole thing is that JavaScript is JavaScript, with all its oddities, this example intrigued me. Is this related to the null type and how it is processed, or how the value comparison operations are performed?
')
In the end, I decided to get to the bottom of what is happening and began to rummage through the only source of truth for JavaScript — the ECMA specification. Today I want to tell you about how deep a rabbit hole I fell as a result.

Abstract comparison algorithm for relationships


Consider the first comparison:

 null > 0; // false 

In accordance with the specification, the comparison operators > and < , in order to find out if the expression is true or false, pass it through the so-called abstract comparison algorithm for relations . Hereinafter, we will quote fragments of the specification on the text of the translation "Standard ECMA-262, 3rd edition" from the resource javascript.ru :

  x < y,  x  y  ,  true, false  undefined ( ,        NaN).     : 1.  ToPrimitive(x,  Number). 2.  ToPrimitive(y,  Number). 3.  ((1))  String  ((2))  String -    16. (,       7      + ,       .) 4.  ToNumber((1)). 5.  ToNumber((2)). 6.  (4)  NaN -  undefined. 7.  (5)  NaN -  undefined. 8.  (4)  (5)     -  false. 9.  (4)  +0  (5)  -0 -  false. 10.  (4)  -0  (5)  +0 -  false. 11.  (4)  +∞,  false. 12.  (5)  +∞,  true. 13.  (5)  -∞,  false. 14.  (4)  -∞,  true. 15.     (4) ,    (5) (,          ) -  true.   false. 16.  (2)   (1),  false. (  p     q,  q     p     r. ,      , .. r    .) 17.  (1)   (2),  true. 18.  k -    ,     k (1)      k (2). ( k  , ..    ,         .) 19.  m - ,       k  (1). 20.  n - ,       k  (2). 21.  m < n,  true.   false. 

Lets go through this algorithm with our expression null > 0 .

Steps 1 and 2 suggest that we call the ToPrimitive() operator for null and 0 values ​​in order to cast these values ​​to their elementary type (such as Number or String , for example). Here's how ToPrimitive translates different values:
Input type
Result
Undefined
No conversion
Null
No conversion
Boolean
No conversion
Number
No conversion
String
No conversion
Object
Returns the default value for an object. The default value for an object is obtained by calling the internal [[DefaultValue]] method for the object with passing it the optional hint PreferredType.

In accordance with the table, neither the left side of the expression, null , nor the right side, 0 , no conversion is applied.

Step 3 of the algorithm is inapplicable in our case, skip it and go further. In steps 4 and 5, we need to convert the left and right sides of the expression to the Number type. The conversion to the Number type is performed in accordance with the following table (here the conversion rules for the input types String and Object are omitted, since they have no relation to the topic of our conversation):
Input type
Result
Undefined
NaN
Null
+0
Boolean
The result is 1 if the argument is true. The result is +0 if the argument is false.
Number
No conversion
...
...

According to the table, null will be converted to +0 , and 0 will remain itself. None of these values ​​is NaN , so the steps of algorithm 6 and 7 can be skipped. But in step 8 we need to stop. The value of +0 is 0 , as a result, the algorithm returns false . In this way:

 null > 0; // false null < 0; //  false 

So, why null no more and no less than zero, we found out. Now we go further - let's deal with why null is also not zero.

Abstract comparison algorithm for equalities


Consider now the test for equality of null and 0 :

 null == 0; //false 

The == operator uses the so-called abstract comparison algorithm for equalities , returning true or false as a result. Here is the algorithm:

  x == y,  x  y  ,  true  false.     : 1.  (x)   (y) -    14. 2.  (x)  Undefined -  true. 3.  (x)  Null -  true. 4.  (x)   Number -    11. 5.  x  NaN -  false. 6.  y  NaN -  false. 7.  x     ,   y, -  true. 8.  x  +0,  y  -0,  true. 9.  x  -0,  y  +0,  true. 10.  false. 11.  (x)  String -  true,  x  y       (        ).   false. 12.  (x)  Boolean,  true,  x  y   true    false.   false. 13.  true,  x  y            ,     (.  13.1.2).   false. 14.  x  null,  y  undefined -  true. 15.  x  undefined,  y  null -  true. 16.  (x)  Number,  (y)  String,    x == ToNumber(y). 17.  (x)  String,  (y)  Number,    ToNumber(x)== y. 18.  (x)  Boolean,    ToNumber(x)== y. 19.  (y)  Boolean,    x == ToNumber(y). 20.  (x) - String  Number,  (y) - Object,    x == ToPrimitive(y). 21.  (x) - Object,  (y) - String  Number,    ToPrimitive(x)== y. 22.  false. 

Trying to understand whether the value of null equal to 0, we immediately go from step 1 to step 14, since (x) (y) . Oddly enough, but steps 14-21 are also not suitable for our case, since () — null . Finally we get to step 22, after which false returned as the default !
As a result, it turns out that:

 null == 0; //false 

Now that another “secret” of JavaScript has been solved, let's deal with the “greater or equal” operator.

Operator greater than or equal to (> =)


Find out now why the following expression is true:

 null >= 0; // true 

Here the specification completely knocked me out of the rut. This is how, at a very high level, the> = operator works:

  null < 0   false,  null >= 0   true 



As a result, we get:

 null >= 0; // true 

And, in fact, it makes sense. Mathematically speaking, if we have two numbers, x and y , and if x not less than y , then x must be greater than or equal to y .

I assume that this operator works exactly in order to optimize the calculations. Why first check whether x greater than y , and if it is not, check whether x equal to y , if you can perform just one comparison, check if x smaller than y , and then use the result of this comparison in order to output the result of the original expression.

Results


The question of comparing null and 0 is actually not so difficult. However, searching for an answer revealed something new to JavaScript. Hope my story did the same for you.

Dear readers! Do you know about any oddities of JavaScript that, after reading the documentation, no longer seem so?

Source: https://habr.com/ru/post/337732/


All Articles