![](http://habrastorage.org/getpro/habr/avatars/dff/fa0/c30/dfffa0c30a9a10a35839c8ee9e275eab.jpg)
JavaScript: test your intuition
![](https://habrastorage.org/getpro/habr/post_images/ade/9bb/322/ade9bb322bafb763c7f503a383036a27.jpg)
After the New Year holidays, I already invited the community to stretch their mind at jigsaw puzzles in JavaScript. Quite a lot of time has passed since that post, there have been many other holidays, so I suggest thinking about a new portion of tasks.
I will hide the answers and my own version of the explanation of why this behavior is logical, as last time, 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. The excellent Russian translation of the ECMAScript 5 specification can help you in solving this , for which many thanks iliakan !
1. The main issue of life, the universe and all that
"3" -+-+-+ "1" + "1" / "3" * "6" + "2"
Decision
As we already know from the last post, the + operator performs either concatenation of strings, or addition, or reduction to a number. Those.
not 5, as you might think.
In addition, you can throw the unary operator “+” or “-” on an expression to change its sign and make things more beautiful and readable.
Given all of the above:
Next, recall the priority of operations: / * +
"3" -+-+-+ "1" + "1" / "3" * "6" + "2" == "42"
As we already know from the last post, the + operator performs either concatenation of strings, or addition, or reduction to a number. Those.
“3” + 2 == “32”
not 5, as you might think.
In addition, you can throw the unary operator “+” or “-” on an expression to change its sign and make things more beautiful and readable.
Given all of the above:
+ “1” === 1
-+ “1” === -1
+-+ “1” === -1
…
-+-+-+ === -1
"3" -+-+-+ "1" === 2 //вычитание производится над числами
Next, recall the priority of operations: / * +
“1”/”3” === 0.3333…
“1” / ”3” * ”6” === 2
2 + 2 === 4
4 + “2” === “42”
2. Maximalism
Math.max(3, 0);
Math.max(3, {});
Math.max(3, []);
Math.max(-1, [1]);
Math.max(-1, [1, 4]);
Math.max(3, true);
Math.max(3, 'foo');
Math.max(-1, null);
Math.max(-1, undefined);
Decision
Everything is simple here.
try to execute toNumber for {}:
execute valueOf and check if it is primitive - no, then
execute toString and get "[object Object]" ;
execute for the resulting string toNumber and get NaN ;
if NaN is received, Math.max () always returns NaN .
let's try to execute toNumber for []:
execute valueOf and check if this is primitive - no, then
execute toString and get "";
execute for the resulting string toNumber and get 0;
3> 0
we will try to execute toNumber for [1]: we
will execute valueOf and we will check whether it is primitive - no, then we
will execute toString and we will receive "1";
execute for the resulting string toNumber and get 1;
-1 <1
try to execute toNumber for [1,4]:
execute valueOf and check if it is primitive - no, then
execute toString and get “1,4”;
execute for the resulting string toNumber and get NaN ;
if NaN is received, Math.max () always returns NaN .
try to execute toNumber for true :
execute valueOf and check if this is primitive - yes, then
3> 1
for 'foo' toNumber returns NaN .
If NaN is received, Math.max () always returns NaN .
if NaN is received, Math.max () always returns NaN .
Math.max(3, 0); // 3
Everything is simple here.
Math.max(3, {}); // NaN
try to execute toNumber for {}:
execute valueOf and check if it is primitive - no, then
execute toString and get "[object Object]" ;
execute for the resulting string toNumber and get NaN ;
if NaN is received, Math.max () always returns NaN .
Math.max(3, []); // 3
let's try to execute toNumber for []:
execute valueOf and check if this is primitive - no, then
execute toString and get "";
execute for the resulting string toNumber and get 0;
3> 0
Math.max(-1, [1]); // 1
we will try to execute toNumber for [1]: we
will execute valueOf and we will check whether it is primitive - no, then we
will execute toString and we will receive "1";
execute for the resulting string toNumber and get 1;
-1 <1
Math.max(-1, [1, 4]); // NaN
try to execute toNumber for [1,4]:
execute valueOf and check if it is primitive - no, then
execute toString and get “1,4”;
execute for the resulting string toNumber and get NaN ;
if NaN is received, Math.max () always returns NaN .
Math.max(3, true); // 3
try to execute toNumber for true :
execute valueOf and check if this is primitive - yes, then
toNumber(true) === 1
3> 1
Math.max(3, 'foo'); // NaN
for 'foo' toNumber returns NaN .
If NaN is received, Math.max () always returns NaN .
Math.max(-1, null); // 0
toNumber(null) === 0
-1 < 0
Math.max(-1, undefined); // NaN
toNumber(undefined) === NaN
if NaN is received, Math.max () always returns NaN .
3. Life comma
[,,,].join()
[,,,undefined].join()
Hidden text
Here I can only refer to Flanagan. 7.1:
“If an array literal contains several consecutive commas with no values between them, a sparse array is created. Elements corresponding to such missing values are absent in the array, but when they are accessed, the value is undefined. "
" The syntax of array literals allows you to insert an optional trailing comma. "
Why is this not clear to me. In the comments on the last post, this was presented as a feature. In my opinion, this is still a browser crutch from errors in the code.
[,,,].join() // ",,"
[,,,undefined].join() // ",,,"
Here I can only refer to Flanagan. 7.1:
“If an array literal contains several consecutive commas with no values between them, a sparse array is created. Elements corresponding to such missing values are absent in the array, but when they are accessed, the value is undefined. "
" The syntax of array literals allows you to insert an optional trailing comma. "
Why is this not clear to me. In the comments on the last post, this was presented as a feature. In my opinion, this is still a browser crutch from errors in the code.
4. Treasure Map
Array(20).map(function(elem) { return 'a'; });
Hidden text
Calling the Array constructor with one argument does not create an array of 20 elements, but an array with a length of 20. And the map method first creates an empty array whose length is equal to the length of the transferred array, and then calls a callback for each element of the transferred array. In our case, the array has no elements and the method returns an empty array of the same length as the original.
Array(20).map(function(elem) { return 'a'; }); // Array of undefined x 20
Calling the Array constructor with one argument does not create an array of 20 elements, but an array with a length of 20. And the map method first creates an empty array whose length is equal to the length of the transferred array, and then calls a callback for each element of the transferred array. In our case, the array has no elements and the method returns an empty array of the same length as the original.
5. Finita la comedia
isFinite(42);
isFinite(1/0);
isFinite(0/0);
isFinite('42');
isFinite('hi');
isFinite();
isFinite(undefined);
isFinite(null);
Hidden text
isFinite converts the argument to a number, and if it turns out NaN, + Infinity or -Infinity , then returns false . In all other cases, true .
ToNumber from 'hi' will return NaN , undefined will return NaN , and null will return 0.
isFinite(42); // true
isFinite(1/0); // false
isFinite(0/0); // NaN is not finite -> false
isFinite('42'); // true
isFinite('hi'); // false
isFinite(); // false
isFinite(undefined); // false
isFinite(null); // true
isFinite converts the argument to a number, and if it turns out NaN, + Infinity or -Infinity , then returns false . In all other cases, true .
ToNumber from 'hi' will return NaN , undefined will return NaN , and null will return 0.
6. True story bro
'true' == true
Hidden text
The equality operator sequentially leads to numbers first true, then 'true'. It turns out NaN == 1, which is obviously false.
'true' == true //false
The equality operator sequentially leads to numbers first true, then 'true'. It turns out NaN == 1, which is obviously false.
7. Nothingness
null == false
!null
Hidden text
With casting null to bool, everything is clear. We will deal with the comparison. the combination of null and bool does not fall under any of the comparison \ cast options in clause 11.9.3 of the specification and therefore the comparison returns false .
null == false // false
!null // true
With casting null to bool, everything is clear. We will deal with the comparison. the combination of null and bool does not fall under any of the comparison \ cast options in clause 11.9.3 of the specification and therefore the comparison returns false .
8. Uncertainty Testing
/^[a-z]{1,10}$/.test(null);
/^[a-z]{1,10}$/.test(undefined);
Hidden text
Null and undefined are cast to the string as is: “null” and “undefined” - and such strings satisfy the regular expression. And NaN , by the way, will also become “NaN.”
/^[a-z]{1,10}$/.test(null); //true
/^[a-z]{1,10}$/.test(undefined); //true
Null and undefined are cast to the string as is: “null” and “undefined” - and such strings satisfy the regular expression. And NaN , by the way, will also become “NaN.”
9. Negation of zero
0 === -0
1/0 === 1/-0
Hidden text
Zero is negative zero, but when dividing with a sign, the sign is taken into account and it turns out
0 === -0 //true
1/0 === 1/-0 //false
Zero is negative zero, but when dividing with a sign, the sign is taken into account and it turns out
Infinity === -Infinity
For those heroes who have read to the end, perhaps the most interesting puzzle. I do not want to hide the explanation under another spoiler, so I advise you after you give the answer, open devtools and check there. It is likely that the result will surprise you and you will want to think again.
10. Slash
n = 1
/1*"\/\//.test(n + '"//')
n = 1;
/1*"\/\//.test(n + '"//');
Hidden text
A slash can be used in three cases: regular expression, division, and comment. Here, at first glance, we see only a regular expression. But, in fact, without a semicolon, the first slash performs division. Thus, division is first performed, and then the result is multiplied by a string. The remaining tail remains just a comment. The line by which we multiply to the number is not reduced and NaN is obtained .
n = 1
/1*"\/\//.test(n + '"//') //NaN
n = 1;
/1*"\/\//.test(n + '"//'); //true
A slash can be used in three cases: regular expression, division, and comment. Here, at first glance, we see only a regular expression. But, in fact, without a semicolon, the first slash performs division. Thus, division is first performed, and then the result is multiplied by a string. The remaining tail remains just a comment. The line by which we multiply to the number is not reduced and NaN is obtained .