Recently I saw a tweet about the relationship between values in JavaScript saying that greater or equals means nothing. The tweet reported the following results:

```
null >= 0 // true
null > 0 // false
null == 0 // false
```

My experience with the JavaScript language makes me believe that everything has a meaning, even if it looks weird or like a malfunction on a higher level. So, I took some time to investigate the ECMAScript specs to understand how to explain these results.

`null >= 0`

is `true`

I started with the first case. Why does `null >= 0`

come out as `true`

? I couldn’t say. So, I searched in the specs where `>=`

is defined and found the relational operators:

```
RelationalExpression[?In, ?Yield] >= ShiftExpression[?Yield]
```

Now, I needed to find how the RelationalExpression is evaluated:

```
RelationalExpression : RelationalExpression >= ShiftExpression
1. Let lref be the result of evaluating RelationalExpression.
2. Let lval be ? GetValue(lref).
3. Let rref be the result of evaluating ShiftExpression.
4. Let rval be ? GetValue(rref).
5. Let r be the result of performing Abstract Relational Comparison lval < rval.
6. ReturnIfAbrupt(r).
7. If r is true or undefined, return false. Otherwise, return true.
```

Running through the evaluation step by step, I could say that `lref`

is `null`

, and `lval`

is the result of `GetValue(lref)`

. This means that `lval`

will be `null`

:

```
6.2.3.1 GetValue (V)
...
2. If Type(V) is not Reference, return V.
...
```

The same happens with the `0`

operand, where `rref`

and `rval`

will be `0`

.

The important part, you might notice, is at step 5: performing `Abstract Relational Comparison lval < rval`

. Let’s check out what it does:

```
1. If the LeftFirst flag is true, then
a. Let px be ? ToPrimitive(x, hint Number).
b. Let py be ? ToPrimitive(y, hint Number).
```

The comparison here is not provided by a `LeftFirst`

flag, and it’s default value is `true`

, so `px`

is the result of `ToPrimitive(x, ...)`

and `py`

is the result of `ToPrimitive(y, ...)`

. As both `null`

and `0`

are primitive values, `ToPrimitive`

returns them without any conversion. Now, we can proceed to the following steps:

```
3. If both px and py are Strings, then
```

We know both `px`

and `py`

are not Strings though, right?

```
4. Else
a. Let nx be ? ToNumber(px). Because px and py are primitive values evaluation order is not important.
b. Let ny be ? ToNumber(py).
```

The above reflects the most important point that defines the final result for the `>=`

relationship operation. The values will be converted to their number representation. You can check the `ToNumber`

method to understand that `null`

is converted to `+0`

and `0`

as a Number value has no conversion.

Now, we know `nx`

is `+0`

(or simply `0`

) and `ny`

is `0`

too, and they meet in the following step 4.e:

```
4. Else
...
e. If nx and ny are the same Number value, return false.
```

Remember that the Abstract Relational Comparison was called to compare if `x < y`

, and for sure, that is false. If we go back to our RelationalExpression evaluation, we find the final result at step 7:

```
RelationalExpression : RelationalExpression >= ShiftExpression
...
5. Let r be the result of performing Abstract Relational Comparison lval < rval.
...
7. If r is true or undefined, return false. Otherwise, return true.
```

As `r`

is false, the evaluation returns the opposite value, `true`

.

Returning back to `null >= 0`

, we can finally say the relational comparison of `null`

and `0`

is made from their numeric representation. The number that represents `null`

is `0`

, so it makes it more clear to say the operation is the equivalent for `0 >= 0`

. I’m sure you will agree with me that’s `true`

.

Let’s see what happens on the next operation.

`null > 0`

is `false`

The `>`

on `null > 0`

is another relational operator, and it is evaluated as the following:

```
RelationalExpression : RelationalExpression > ShiftExpression
1. Let lref be the result of evaluating RelationalExpression.
2. Let lval be ? GetValue(lref).
3. Let rref be the result of evaluating ShiftExpression.
4. Let rval be ? GetValue(rref).
5. Let r be the result of performing Abstract Relational Comparison rval < lval with LeftFirst equal to false.
6. ReturnIfAbrupt(r).
7. If r is undefined, return false. Otherwise, return r.
```

This case is very similar to the previous one we explored, with the difference being that Abstract Relational Comparison is now called with `LeftFirst`

being `false`

. This means only the value on the right is parsed first on the `ToPrimitive`

operation:

```
7.2.12 Abstract Relational Comparison
1. If the LeftFirst flag is true, then
...
2. Else the order of evaluation needs to be reversed to preserve left to right evaluation
a. Let py be ? ToPrimitive(y, hint Number).
b. Let px be ? ToPrimitive(x, hint Number).
```

As we’ve seen before, both `null`

and `0`

are already their primitive representations, so they remain with the same values for `py`

and `px`

and will pass through the same `ToNumber`

operation on steps 4.a and 4.b.

What’s the result after evaluating `0 < 0`

?

`false`

- An emoji representing me (Leo) wearing my round glasses and looking to your left

Unfortunately, in JavaScript, this is not an emoji operator, and it simply returns `false`

as you can see here:

```
RelationalExpression : RelationalExpression > ShiftExpression
...
5. Let r be the result of performing Abstract Relational Comparison rval < lval with LeftFirst equal to false.
...
7. If r is undefined, return false. Otherwise, return r.
```

Now that we know both `>=`

and `<`

compare the left and right values using their numeric representations, what happens with the `==`

operator?

`null == 0`

is `false`

As I mentioned before, `>=`

and `<`

are both relational expressions and based on the relationship named by the operator between the numeric representation of both operands. This is different for the `==`

operator, which is not a relational expression anymore, it’s actually a equality operator

```
EqualityExpression[In, Yield]:
RelationalExpression[?In, ?Yield]
EqualityExpression[?In, ?Yield] == RelationalExpression[?In, ?Yield]
...
```

Notice that the operands can be a relational expression. I’m not going to explain it in this post, but this means we can compare their results, such as `null >= 0 == null < 0`

evaluated as `true == false`

returning `false`

.

Let’s check how this evaluation happens:

```
EqualityExpression : EqualityExpression == RelationalExpression
1. Let lref be the result of evaluating EqualityExpression.
2. Let lval be ? GetValue(lref).
3. Let rref be the result of evaluating RelationalExpression.
4. Let rval be ? GetValue(rref).
5. Return the result of performing Abstract Equality Comparison rval == lval.
```

The first four steps are similar to what we’ve seen before in the evaluation for relational expressions. We know on `null == 0`

the values for `lval`

is `null`

and `rval`

is `0`

.

Now, we have to check the result of `Abstract Equality Comparison rval == lval`

.

```
7.2.13 Abstract Equality Comparison
1. If Type(x) is the same as Type(y), then
a. Return the result of performing Strict Equality Comparison x === y.
2. If x is null and y is undefined, return true.
3. If x is undefined and y is null, return true.
4. If Type(x) is Number and Type(y) is String, return the result of the comparison x == ToNumber(y).
5. If Type(x) is String and Type(y) is Number, return the result of the comparison ToNumber(x) == y.
6. If Type(x) is Boolean, return the result of the comparison ToNumber(x) == y.
7. If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
8. If Type(x) is either String, Number, or Symbol and Type(y) is Object, return the result of the comparison x == ToPrimitive(y).
9. If Type(x) is Object and Type(y) is either String, Number, or Symbol, return the result of the comparison ToPrimitive(x) == y.
10. Return false.
```

We can see there’s no `ToNumber`

conversion on the operands, we are now checking their actual value representation, not even a `ToPrimitive`

conversion is happening here.

If we run through the given steps, we end up on step 10, which returns `false`

, and that’s the final result for our `null == 0`

operation.

### Isn’t `null`

an object?

You might consider `null`

an object because `typeof null`

returns `"object"`

. That’s misleading because the real type of `null`

is **null** and not an **Object**. You can check it at the value types we have specified.

That’s why `null`

values don’t return on the steps 8 or 9 on the abstract equality comparison:

```
7.2.13 Abstract Equality Comparison
...
8. If Type(x) is either String, Number, or Symbol and Type(y) is Object, return the result of the comparison x == ToPrimitive(y).
9. If Type(x) is Object and Type(y) is either String, Number, or Symbol, return the result of the comparison ToPrimitive(x) == y.
...
```

The `Type`

for `null`

is not `Object`

, and `null == 0`

is finally `false`

for any matters.

## Conclusion

As humans, we tend to see `>=`

, `<`

, and `==`

leading to the same mathematical comparisons, but JavaScript is a programming language and not a scientific calculator even if it’s a great tool for the Internet of Things. These differences are fine on JavaScript as even constant values such as PI are represented only by an approximate numerical value as you can see in the specs for Math.PI.

While the `null >= 0`

and `null < 0`

are comparing their relationship using their numeric representations, `==`

is not a mathematical comparison, but a check for the operandsâ€™ equivalency represented by their native values in the language. Their relationship is evaluated as simply programming language values.

Rather than categorizing something as a *wat* moment on a programming language, itâ€™s more useful to explore and understand how and why it works out that way. Doing so might even help to figure out the most appropriate question for the presented cases: why is your code trying to compare `null`

with `0`

?

I hope you can now see more clearly what is happening for these distinct operators so that their results are less confusing. Do you have any suggestions or feedback? Let’s discuss it! My appreciation is `== 1`

.

## Comments

We moved off of Disqus for data privacy and consent concerns, and are currently searching for a new commenting tool.

\”is null and not and Object\” -> \”is null and not an Object\”

Thank you, Trevor!

Thank you for such a well-written and in-depth article, Leo!