The recent
report by Harry Bernhardt on CodeMash has turned out to be quite popular (note. Per .: including on
Habré ). In the report, he jokes about some features of the behavior of ruby and javascript.
I can hardly convince you that there is any point in what Harry complains about. However, I hope I can explain to you why javascript behaves this way.
+ Symbol
The + symbol in javascript can mean three things.
This can be a binary addition operator that applies to two numbers.
This can be a binary addition operator applied to two lines.
This may be the unary operator “this number is positive”, applied to one number.
Everything makes it a little harder to automatically cast types in javascript. For example, if before or after the + character there are no strings or numbers, javascript automatically converts the operands to either strings or numbers.
')
boolean, null, undefined
converted to
numbers (
true = 1, false = 0, null = 0, undefined = NaN
)
objects, arrays, functions are converted to
strings .
So now when you see
[] + []
you understand that javascript converts both empty arrays to strings and adds the resulting two strings.
When an array is converted to a string, you get a string containing a comma-separated list of its elements. Therefore, for an empty array, we get an empty string.
[] + {}
In this case, the empty object on the right will also be converted to a string. Since it does not implement the
toString
method, in accordance with inheritance, the
toString
method of Object will be used, which returns the string
"[object Object]"
for objects. Therefore, in this example, we add an empty string with the string
"[object Object]"
.
Empty code blocks
Now consider the oddities of the javascript parser. You may have noticed that we use curly brackets in javascript for two different purposes. To designate code blocks (for example, after
if
or as part of a function definition) and to write objects in object notation (also called JSON). In some programming languages, code blocks can be used in many places within existing code to define a new scope. Javascript (so far) does not use scope at the level of code blocks, however, it allows the use of code blocks inside code. So, sometimes, when you write
{}
, the javascript parser takes it as an empty block of code, and sometimes as an empty object.
Generally speaking, if the brace is at the beginning of an expression, it will be interpreted as the beginning of a block of code. You can force the javascript parser to process it as an object, enclosing it in ordinary brackets.
{} + []
In this case, the empty braces are treated as an empty code block, which means that + is at the beginning of the next statement, i.e. will be interpreted as an operator denoting the number following it as positive. The prefix operator + takes as input a single numeric argument, so it will always cast its argument to a number.
An additional trick is that javascript brings an object, function or array to a number, leading them to a string beforehand. An empty array is reduced to zero. For example:
+ [] === 0 + [1] === 1 isNaN(+[1, 2] ) +({toString: function() {return "3"}}) === 3
So, an empty object is cast to the string
"[object Object]"
, which is
NaN
to
NaN
when it has to be converted to a number due to the prefix operator +.
{} + {}
Symbol -
Unlike +, the symbol is fairly simple. It has only two values: a binary operator that applies to two numbers, and a prefix operator that applies to the same number. As you already know, strings that are not numbers are
NaN
to
NaN
if they are to be used as numbers. Therefore, you should not be surprised that
isNaN("wat" - 1)
Why is it important?
Only a few of the points mentioned can occur and are encountered in practice. Long ago, when people used
eval
to parse JSON, they had to wrap their JSON in brackets so that the parser did not accidentally take it as a block of code. It is often important to remember the type of variables and convert your strings to numbers, because otherwise people will be surprised to see 3 + 1 = 31. Knowing the cases when type casting will make a large number of rules about
== false
much less confusing. And, most importantly, it will allow you to be among the listeners of the report “javascript has gone crazy” and to behave as if everything that is happening is completely logical for you (and there seem to be few such).