📜 ⬆️ ⬇️

Javascript: check your intuition


On Habré already warmed up and amused themselves with the seeming illogicalities of JavaScript. In my opinion, such examples are a great way to stretch your brains after long New Year holidays, so I suggest you think over 10 puzzles.

Answers and my own explanation of why this behavior is logical, I will hide under the spoiler. Immediately make a reservation that I do not pretend to the unshakable truth of my versions and I will be glad to discuss them. An excellent Russian translation of the ECMAScript 5 specification can help you to solve this problem, for which many thanks iliakan !


1. So remember, children, always substitute number systems!

For a start, a simple but cool example. What will return such calls parseInt?
parseInt('fuck'); parseInt('fuck', 16); 

Decision
 parseInt('fuck'); // NaN parseInt('fuck', 16); // 15 

How parseInt works: it character-by-character checks the passed string for compliance with the indicated second argument to the number system and if it finds an incorrect character, it terminates. By default, the number system is considered decimal. In not the most recent browsers, if the transferred string starts from 0, then by default the system is considered octal. In the decimal number system, the 'f' character is invalid and the function ends its work without finding a single number. But in the hexadecimal system, the character 'f' is valid and corresponds to a decimal number 15. The character 'u' is not valid and the function ends its work.

')
2. Can someone tell me?

What is the expression?
 "Why am I a " + typeof + ""; 

Decision
 “Why am I a number” 

The “+” operator has a higher priority than “typeof”, therefore the specified entry is equivalent to the following:
 “Why am I a ” + (typeof (+ “”)). 

The unary “+” performs a cast to a number, so the “typeof” from the result of its execution is number.


3. Who is more?

Well, who is more?
 [1, 2, 4] < [1, 2, 5] [1, 2, 'd'] < [1, 2, 5] [1, 2, ['d', 5]] < [1, 2, [20, 5]] [1, 2, 5] == [1, 2, 5] [1, 2, 5] <= [1, 2, 5] [1, 2, 5] >= [1, 2, 5] 

Decision
 [1, 2, 4] < [1, 2, 5] //true [1, 2, 'd'] < [1, 2, 5] //false [1, 2, ['d', 5]] < [1, 2, [20, 5]] //false [1, 2, 5] == [1, 2, 5] //false [1, 2, 5] <= [1, 2, 5] //true [1, 2, 5] >= [1, 2, 5] //true 

According to the ECMAScript 5 specification, in order to perform a comparison operation, arguments that are not primitives should be referred to primitives (if you are interested, then clause 11.8.5 “Abstract Ratio Comparison Algorithm”). First, JavaScript tries to convert the argument to a number using the valueOf method and only when this fails leads to a string type (I originally wanted to write here about the naturalness of comparing numbers, and that when we say that word A is more than word B, we mean the length But from a conversation with a colleague it turned out that this is not true. When we compare two words, we instantiate the images associated with them and compare them. And only if there are no images, we compare the words not as image labels, but as a set of letters. For arrays, the valueOf method is not defined and therefore they are compared as strings:
 "1,2,4" < "1,2,5" //true "1,2,d" < "1,2,5" //false 

But all of the above is true only for comparison operations. In the case of the “==” operator, priming is performed only if one of the arguments is primitive, and in all other cases the == operator returns true only if both arguments refer to the same object (clause 11.9.3 “Abstract Equality Comparison Algorithm” ) what is wrong in our case.

It should be noted that comparison will not work for objects, since their default toString returns [object Object].


4. Who is more? -2

Based on the previous riddle, or rather its solution.
 var obj1 = { test: 'test', toString: function(){ return 10; }, valueOf: function(){ return 100; } } var obj2 = { test: 'test', toString: function(){ return 100; }, valueOf: function(){ return 10; } } obj1 ? obj2 

Decision
 obj1 > obj2 

As was said in the previous decision, when comparing JavaScript, it first tries to bring non-primitive arguments to numbers, i.e. calls the valueOf method. And 100> 10.


5. Infinity of Madness

What will return?
 parseFloat('Infinity'); Number('Infinity'); parseInt('Infinity'); 

Decision
 parseFloat('Infinity'); //Infinity Number('Infinity'); //Infinity parseInt('Infinity'); //NaN 

The number is displayed as infinity when it exceeds the maximum floating point number: 1.7976931348623157E + 308. Those. essentially, Infinity is a constant with a fractional value and therefore it is determined by parseFloat and Number, but not defined by parseInt.


6. Games with pluses

For those who carefully read previous solutions, it is not difficult to say what will return the following expression:
 "foo" + + "bar" 

Decision
 ("foo" + + "bar") === "fooNaN" // true 

Select unary +:
  “foo” + (+ “bar”) 

It’s not hard to see, he will return NaN, since a string cannot be cast to a number. In this way:
 "foo" + NaN === "fooNaN". 



7. The smallest number

Who is bigger?
 Number.MIN_VALUE ? 0 

Decision
 Number.MIN_VALUE > 0 

According to the specification MIN_VALUE is the number closest to 0, which allows JavaScript. Approximately equal to 5e-324. All numbers smaller in absolute value are converted to 0. It’s logical to call it minimal, since the maximum negative is called “the most negative”, but still causes some confusion.


8. Luxury tax

What we see on the screen?
 alert(111111111111111111111); 

Decision
 111111111111111111000 

JavaScript interprets large numbers exponentially:
 111111111111111111111 = 1.11111111111111111111e20. 

But there is not enough accuracy for storing 1.11111111111111111111 and therefore
 (1.11111111111111111111e20).toString() == 111111111111111110000 



9. “Boolean arithmetic”

 (true + 1) === 2;​ (true + true) === 2; true === 2; true === 1; 

Decision
 (true + 1) === 2;​ ​ // true (true + true) === 2; // true true === 2; // false true === 1; // false 

The double “+” operator either adds numbers or concatenates strings. When casting true, the number will return 1.

The operator “===” in contrast to “+” does not perform type casting and therefore true is not strictly equal to one.


10. Negation of Emptiness

 [] == ![] 

Decision
 [] == ![] //true 

A small quote from the rule of type casting in the operator == from the specification:

1. If Type (x) is Number and Type (y) is String, return the result of the comparison x == ToNumber (y).

2. If Type (x) is String and Type (y) is Number, return the comparison result ToNumber (x) == y.

3. If Type (x) is Boolean, return the comparison result ToNumber (x) == y.

4. If Type (y) is Boolean, return the result of the comparison x == ToNumber (y).

5. If Type (x) is either String or Number, and Type (y) is Object, return the result of the comparison x == ToPrimitive (y).

6. If Type (x) is Object and Type (y) is either String or Number, return the result of the comparison ToPrimitive (x) == y.

First, we calculate the right-hand side of the equality and get:
 [] == false 

because the object is always cast to true.
Now, according to rule 4:
 [] == 0 

according to rule 6 and with knowledge of 3 puzzles:
 "" == 0 

Then, according to rule 2:
 0 == 0 

Voila!


Conclusion

How many tasks from the first time you solved correctly? I hope you enjoyed these small exercises. According to subjective feelings, the analysis of such situations is very useful. An excellent reason to look into the documentation and refresh the location of the rake.

If you know other interesting examples, please add hiding answers and explanations to the spoiler in the comments. For my part, I can not resist not to add as a bonus a puzzle from the comments to one of the old articles:

That more?
 Math.min() ? Math.max() 

Decision
 Math.min() > Math.max() 

According to the definition of the Math.max method , if there are no arguments, -Infinity is returned. Similarly, min simply returns Infinity.

And yes, the main thing: do not use it in the combat code! Pity those who will read it.

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


All Articles