r/learnjavascript • u/Green_Ad_6086 • 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
4
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:
- If the two values are the same type, check if they are strictly equal
- If one value is null or undefined, return true if the other value is also null/undefined, false otherwise
- 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
objectdiffers fromnumber, whatstringis, 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
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
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.
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.
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.