How does this check work with operator precedence in JS - javascript

So I'm reading through this precedence table https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence
It says 20 - 1 with 20 being highest precedence.
16 Logical NOT right-to-left ! … So the ! operator has a precedence of 16.
10 Strict Equality … === … So the === operator has a precendence of 10.
This lines
!'hello' === 'goodbye'
How does this get executed/read? By reading it I thought. In steps it goes;
'hello' === 'goodbye' Check then, invert bool value. So If it returns true set it to false.
If i'm reading through the precedence operators table. It looks to me like it does the ! operator first and then ===.
How does it invert a non-bool value beforehand and then do the truthy check? Like how does it work could someone explain?
Thank you!

It looks to me like it does the ! operator first and then ===.
Yes. 16 is a higher number than 10, so ! has a higher precedence than ===, so it is resolved first.
How does it invert a non-bool value beforehand and then do the truthy check?
See the spec for ! which points to ToBoolean which says:
String: Return false if argument is the empty String (its length is zero); otherwise return true.

Related

What is happening in this loose equality comparison of 2 empty arrays

I am struggling with understanding how this snippet works on a basic level
if([] == ![]){
console.log("this evaluates to true");
}
Please help me understand where I got it wrong. My thinking:
First there is operator precedence so ! evaluates before ==.
Next ToPrimitive is called and [] converts to empty string.
! operator notices that it needs to convert "" into boolean so it takes that value and makes it into false then negates into true.
== prefers to compare numbers so in my thinking true makes 1 and [] is converted into "" and then 0
Why does it work then? Where did I get it wrong?
Why does it work then?
TLDR:
[] == ![]
//toBoolean [1]
[] == !true
[] == false
//loose equality round one [2]
//toPrimitive([]); toNumber(false) [3]
"" == 0
//loose equality round two
//toNumber("") [4]
0 === 0
true
Some explanations:
1)
First there is operator precedence so ! evaluates before ==
Negating something calls the internal toBoolean method onto that "something" first. In this case this is an Object (as Arrays are Objects) and for that it always returns true which is then negated.
2)
Now it's up to loose equalities special behaviour ( see Taurus answer for more info) :
If A is an Object ( Arrays are Objects ) and B is a Boolean it will do:
ToPrimitive(A) == ToNumber(B)
3)
toPrimitive([])
ToPrimitive(A) attempts to convert its Object argument to a primitive value, by attempting to invoke varying sequences of A.toString and A.valueOf methods on A.
Converting an Array to its primitive is done by calling toString ( as they don't have a valueOf method) which is basically join(",").
toNumber(false)
The result is 1 if the argument is true. The result is +0 if the argument is false. Reference
So false is converted to +0
4)
toNumber("")
A StringNumericLiteral that is empty or contains only white space is converted to +0.
So finally "" is converted to +0
Where did I get it wrong?
At step 1. Negating something does not call toPrimitive but toBoolean ...
The accepted answer is not correct (it is now, though), see this example:
if([5] == true) {
console.log("hello");
}
If everything is indeed processed as the accepted answer states, then [5] == true should have evaluated to true as the array [5] will be converted to its string counterpart ("5"), and the string "5" is truthy (Boolean("5") === true is true), so true == true must be true.
But this is clearly not the case because the conditional does not evaluate to true.
So, what's actually happening is:
1. ![] will convert its operand to a boolean and then flip that boolean value, every object is truthy, so ![] is going to evaluate to false.
At this point, the comparison becomes [] == false
2. What gets into play then is these 2 rules, clearly stated in #6 in the specs for the Abstract Equality Comparison algorithm:
If Type(x) is boolean, return the result of the comparison ToNumber(x) == y.
If Type(y) is boolean, return the result of the comparison x == ToNumber(y)
At this point, the comparison becomes [] == 0.
3. Then, it is this rule:
If Type(x) is Object and Type(y) is either String or Number,
return the result of the comparison ToPrimitive(x) == y.
As #Jonas_W stated, an array's ToPrimitive will call its toString, which will return a comma-separated list of its contents (I am oversimplifying).
At this point, the comparison becomes "" == 0.
4. And finally (well, almost), this rule:
If Type(x) is String and Type(y) is Number,
return the result of the comparison ToNumber(x) == y.
An empty string converted to a number is 0 (Number("") == 0 is true).
At this point, the comparison becomes 0 == 0.
5. At last, this rule will apply:
If Type(x) is the same as Type(y), then
.........
If Type(x) is Number, then
.........
If x is the same Number value as y, return true.
And, this is why the comparison evaluates to true. You can also apply these rules to my first example to see why it doesn't evaluate to true.
All the rules I quoted above are clearly stated here in the specs.
First, realize that you are comparing two different types of values.
When you use ![] it results in false. You have code (at core it results in this):
if([] == false)
Now the second part: since both values are of different type and you are using "==", javascript converts both value type into string (to make sure that they have same type). It starts from left.
On the left we have []. So javascript applies the toString function on [], which results in false. Try console.log([].toString())
You should get false on the left as string value. On the right we have boolean value false, and javascript does the same thing with it.
It use the toString function on false as well, which results in string value false.
Try console.log(false.toString())
This involves two core concepts: how "==" works and associativity of "==" operator - whether it starts from left or right.
Associativity refers to what operator function gets called in: left-to-right or right-to-left.
Operators like == or ! or + are functions that use prefix notation!
The above if statement will result in false if you use "===".
I hope that helps.

why Operator precedence `and` higher then `or`

in https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence
if and higher then or,1||alert(1)&&alert(2) will alert but no
I think they are the same
Looking at the expression:
1||0&&2
The expression is the same as the following:
1||(0&&2)//because && has greater precedence than ||
In which case 1 is the truthy value so you get 1.
So, with precedence rule this is not going to be like below:
(1||0)&&2//because || has lesser precedence than &&
The reason is simple, multiplications come before additions and I hope you know that... The and is a logical product and the or is a logical addition.
So with logical operators you could rewrite your operation (a||b&&c) such as:
a + b * c
and if a, b, and c are Boolean and you apply the proper Boolean operation, it gives you the right result. You can translate that to one bit binary if you'd like:
&& => 1 * 1 is true, all others are false
|| => 0 + 0 is false, all others are true
why Operator precedence and higher then or
Because that is how the language is defined. If it bothers you, then feel free to parenthesize to make the grouping clear.
Many other languages work this way.
A rule for remembering which has higher precedence is to think of && as multiplication and || as addition (which they are, in a logical sense). Of course, multiplication has higher precedence (binds more tightly) than addition.

null and undefined inconsistent comparison

I'm curious to know why
null == undefined
returns true but
null >= undefined
returns false
Is the inclusion of the greater than operator coercing the values differently?
tl;dr The >= ends up coercing both arguments to numbers in this case: undefined gets coerced to NaN while null gets coerced to 0, which aren't equal. For ==, the spec explicitly defines that null == undefined is true.
The values do, in fact, get coerced in both cases (in a sense, at least - the case with == is special). Let's consider them one at a time, with the help of the spec.
The algorithm for the >= operator uses the "Abstract Relational Comparison Algorithm", which is shared by other relational operators. From the description in the spec, we see that the algorithm does the following:
Converts the arguments to primitives (which null and undefined already are).
Checks if the arguments are Strings (which they are not).
If they are not Strings, the algorithm converts the arguments to numbers (see steps 3.a. and 3.b.) and performs the comparison with the results.
The last point is the key. From the ToNumber table, we see that undefined gets coerced to NaN, and the algorithm considers any comparison with NaN as being falsy (see steps 3.c. and 3.d.). Thus, null >= undefined is false.
For the other case, ==, the story is actually much simpler: the spec explicitly states that null == undefined is true as part of the "Abstract Equality Comparison Algorithm" (see steps 2. and 3.). Thus, null == undefined is true.
In JS == operator coerces values to same type to compare, so 1=="1" is true. Use === operator for exact type matching

javascript comparison crises

I came across the following and was unable to grasp the reason, can anyone explain please?
var foo = [0];
console.log(foo == !foo); // true
console.log(foo == foo); // true
The second comparison is simple to explain: foo is equal to itself.
The first one, however, is a bit tricky: foo is an array, which is an object, which evaluates to true when coerced to boolean. So !foo is false. But foo on the left side of the comparison is not being converted to boolean. Both operands are actually converted to numbers during the equality comparison. This is how it evaluates:
[0] == false
[0] == 0
"0" == 0
0 == 0
true
According to MDN, on comparisons with the equality operator ==:
If the two operands are not of the same type, JavaScript converts the operands then applies strict comparison. If either operand is a number or a boolean, the operands are converted to numbers if possible
I know this explanation sounds superficial. It's actually much more complicated than that, but the basic steps are the ones I listed above. You can see the details on the ECMA-262 specification, particularly on sections 9 and 11.9.
You should use "===" and "!==" instead of "==" and "!="
More explanations there:
Which equals operator (== vs ===) should be used in JavaScript comparisons?
http://net.tutsplus.com/tutorials/javascript-ajax/the-10-javascript-mistakes-youre-making/

Unexpected result from expression using &

Here if
document.write(eval("(2 == 2)"));
it prints true
And
document.write(eval("(2 == 2)&(5<10)"));
it prints 1
Why not it always returns true or false.If conditions increases in string it gives 0 or 1.What is the way to get same type of result.
Because & isn't a logical operator, it's a bitwise (numeric) operator. You probably meant &&, the logical AND operator.
Note that there's no reason for using eval in your code examples. (There's almost never any reason to use eval, there's almost always a better alternative — in this case, you don't even need an alternative.) Removing it would have exactly the same result.
It prints 1 because you used the bitwise and operator (&) instead of the logical and operator (&&).
And because JavaScript is loosely typed it will treat the boolean value true as an int value of 1, which you can check by invoking
document.write(eval("(2 == 2)+(5<10)"));
the result will be
2
& is a bitwise operator and returns a number. Try "(2 == 2)&&(5<10)"

Categories