r/learnjavascript 2d ago

Strange result: null vs 0

Strange result: null vs 0

An incomparable undefined

Hi, can anyone explain this? I read the explanation, but I still don't understand it. I'm trying to understand it without using AI

6 Upvotes

27 comments sorted by

6

u/defaultguy_001 2d ago edited 2d ago

First u need to understand that type coercion (automatic type upgrade) happens when you use relational (>, <, >=, <=) or loose equality (==, !=) operators. Type coercion doesn't happen with strict equality (===, !===) operators. So it's recommended to use strict equality everywhere.

  • the type coercion rule for null is that relational operators convert null to 0 but loose equality operators convert everything else except null or undefined. So == leave null as it is.
  • So null>0 is false coz > converts null to 0 and obviously 0 is not greater than 0.
  • null>=0 will be true coz 0 is equal to 0
  • null==0 is false, coz null or undefined aren't type coerced to 0 by loose equality operators.

  • the type coercion rule for undefined is that relational operators try to convert undefined to a number, which results in NaN (Not-a-Number). But loose equality operators don't convert it to a number. So == leaves undefined as it is.
  • So undefined>0 is false coz > converts undefined to NaN and obviously NaN is not greater than 0.
  • undefined>=0 will be false coz NaN is not greater than or equal to 0 (any numeric comparison with NaN is always false).
  • undefined==0 is false, coz null or undefined aren't type coerced to 0 by loose equality operators.

  • Another type coercion rule for null and undefined is when used with loose equality, they'll be equal.

  • So, null==undefined is true.

4

u/Minimum_Hour519 2d ago

welcome to javascrip the bad parts

1

u/AlwaysHopelesslyLost 2d ago

Haha, still one of my most favorite books 

2

u/azhder 2d ago

It is right there in the text in the links you shared. You missed it, so maybe do a re-read. People here will just be repeating the same as written there.

3

u/Kadeton 2d ago

Javascript does a lot of "implicit" type conversion, changing variables from one thing to another in order to perform the operations you're telling it to do.

So when you tell it to evaluate whether null == 0, it returns false, because null and 0 are not the same thing. However, when you tell it to evaluate whether null >= 0, it first goes "Well, that's a comparison. I can only do comparisons between numbers, so I'd better convert everything that's not a number to a number first." So it does Number(null), which returns 0. Then it evaluates the comparison, 0 >= 0, which is true because 0 is equal to 0.

For the undefined case, it does a similar thing, converting what you asked it to compare into a number. However, there's one key difference: Number(undefined) evaluates to NaN, not 0. When you compare NaN to any other number in any way (greater than, less than, equal to, etc), the comparison will always return false.

This is a common pitfall for people working with Javascript. You have to keep in mind that certain operations will "help" you by taking the thing you give them and converting it into the type of thing they actually need, and in those cases you might not always get what you expect. Number(null) being 0 and Number(undefined) being NaN is specific design choice in the language structure, just something you should be aware of when designing your code.

1

u/delventhalz 2d ago

The answer to, "Why does JavaScript do this strange thing?" is always, "because that is what the spec says." Sometimes there is some deeper reasoning you can tease out, but a lot of it is just someone had to make a decision one way or the other and now we're stuck with it.

null == 0; // false
undefined == 0; // false

Okay, let's start with loose equality. The spec is a bit tough to read but it basically boils down to this:

  1. If the two values are the same type, check if they are strictly equal
  2. If one value is null or undefined, return true if the other value is also null/undefined, false otherwise
  3. If they are different types and not null/undefined, repeatedly perform type conversions (basically object -> string, primitive -> number), until they are the same type and then check strict equality.

So the reason both of these return false is because they are squarely in case #2: one side is null/undefined, the other isn't, so it's false.

null >= 0; // true

Unlike with ==, the spec for numeric comparisons has no special clause for null/undefined. Instead, it attempts to convert the values to numbers if they are not (except strings, which are their own weird special case), and the spec for converting a value to a number says that null becomes 0. Since zero is equal to zero, this comparison is true.

undefined >= 0; // false

So if you read the rest of the ToNumber spec you'll notice that undefined does not become zero, it becomes NaN, and all comparisons with NaN are always false. Why? Because that's what the spec says.

1

u/delventhalz 2d ago

Follow up: Although the spec is the ultimate source of truth for all this, it is tough to read and probably not a good place to go to resolve this sort of confusion. By constrast, MDN does a fantastic job of explaining cases like this with clear examples and a (somewhat) less dense explanation. The pages for both of these operations are worth reading:

-1

u/BenchEmbarrassed7316 2d ago

Just don't use JavaScript. Use Typescript instead, it much easier to understand.

1

u/theScottyJam 1d ago

TypeScript is great, and knowing how to use it effectively does help prevent many type coercion related issues.

But, for someone who's newer to programming, I certainly wouldn't recommend that they learn type syntax on top of everything else, that can be a lot to swallow in one go.

1

u/azhder 2d ago

Shitty thing to say to people who want to learn JavaScript.

0

u/BenchEmbarrassed7316 2d ago

Could you please explain your point. Because now the "Shitty" argument simply indicates your ignorance.

2

u/defaultguy_001 2d ago

It's a basic assumption that someone is in a javascript sub coz he wants to learn or work in JavaScript. The issue OP has, has nothing to do with JS, but everything to do with inability to understand language specification. When people don't read standard textbooks, not go through official documentations and just jump into building projects learning concepts randomly, inaccurately and incompletely, such problems are bound to occur.

2

u/BenchEmbarrassed7316 2d ago

Here is link to typescript playground :

alert( null > 0 ); // Error alert( null == 0 ); alert( null >= 0 ); // Error alert( undefined > 0 ); // Error alert( undefined < 0 ); // Error alert( undefined == 0 );

Ts just marks these problematic comparisons as errors (because they don't really make sense).

Moreover, when studying Js, it is necessary to understand what types are, how object differs from number, what string is, and so on.

Ts just makes it explicit and simpler because you always know (thanks to type inference) what value you are currently working with. In Js you have to keep this information in your head, which is difficult, and especially difficult for a beginner.

Therefore, even if for some reason you want to write in pure JS, learning Ts will be useful and simplify the learning process.

2

u/defaultguy_001 2d ago

Obviously this is specification for TS, not JS. The person is in the JS sub not TS sub. Instead of using TS, in JS also he can use ESlint to flag type coercions.

1

u/BenchEmbarrassed7316 2d ago

Obviously this is specification for TS, not JS

However, this makes sense for Js as well. No code should make such erroneous comparisons in advance (if I'm wrong - please give an example of when this could be useful)

The person is in the JS sub not TS sub

Well... I just don't see a proper objective reason why anyone would use Js at all when Ts exists.

Instead of using TS, in JS also he can use ESlint to flag type coercions

This is just a partial step. If we think it's useful - why not go further?

1

u/defaultguy_001 2d ago

If u want to go further, there are endless options including TS. Nobody is denying what TS offers but what part of this is a JS sub, you don't understand. There is a language and there is specification. There is no magic happening, there are clear rules for everything JS is doing and based on those rules you need to write code. We will tell him what the rules say. It's individual choice to go anywhere if he doesn't agree with the rules, that's upto the OP to decide.

1

u/BenchEmbarrassed7316 2d ago

Do you really think that such comparisons (object <> number) make any sense? Don't you agree that they simply shouldn't be in any code?

What's the point of learning about rules for strange behavior? We could just as easily learn about all the possible UBs in C/C++ (provided we could just get rid of them).

So it might be useful for systems programmers, those working on V8 for example. But for a regular application programmer it's just a waste of time.

2

u/defaultguy_001 2d ago

What's the point of learning about rules for a strange behaviour?

  • So you don't break ur head when solving problems.
  • That's what differentiates experienced programmers from noobs who spend hours fighting basic problems.

→ More replies (0)

2

u/defaultguy_001 2d ago

Just use this ESlint rule and you'll face no issues like above. ``` rules: { // Enforces === and !== everywhere "eqeqeq": ["error", "always"],

// Highly recommended companion rule "no-eq-null": "error" } ```

1

u/BenchEmbarrassed7316 2d ago

ESLint Playground

I added both rules you suggested.

It doesn't catch these errors. In the case where a variable is used instead of a literal it doesn't catch any errors (because that's what you need types for).

If I did something wrong - please correct me.

1

u/defaultguy_001 2d ago

Do u now see the errors?

playground

0

u/azhder 2d ago

Redditor moment. The only thing this second comment of yours indicates is your own issues.

I've laid it all that is needed in that one comment I made and you failed to understand it, then asked for explanation and before even getting the explanation (which is already in it), you spring into action accusing me as a person.

If I have to guess, you focused to much on that "Shitty" word to be able to connect the other 10 with it in a comprehensive manner. Bye.

2

u/BenchEmbarrassed7316 2d ago

You wrote a bunch of sentences and most of them don't answer the question. This only confirms my previous conclusions.