The String
global object is a constructor for strings, or a sequence of characters.
String(-0) // '0'
Number('-0') // -0
The only reason for this is ECMAScript Team's decision.
The team has decided to lie to the user when stringifying -0
because most people don't know what a -0
is it for. I'm one of those guys, btw.
- ECMAScript® 2015 Language Specification - ToString Applied to the Number Type
- Kyle Simpsons - What the... JavaScript? (YouTube)
- 2ality - JavaScript’s two zeros
String(null) // 'null'
String([null]) // ''
String(undefined) // 'undefined'
String([undefined]) // ''
By definition when converting null
or undefined
to a string we get the 'null'
and 'undefined'
string respectively.
On the other hand, when converting an object to a string JavaScript tries to convert it to an non-object type. For array it tries to convert it to a string by executing the method .toString()
. By definition toString
applies the string conversion to all array elements and joins them into one string. However, if an element is undefined
or null
, it is converted to the empty string.
- ECMAScript® 2015 Language Specification - ToString
- Kyle Simpsons - What the... JavaScript? (YouTube)
var s = Symbol('Hello World') // Symbol(Hello World)
String(s) // 'Symbol(Hello World)'
s + '' // TypeError: Cannot convert a Symbol value to a string
The reason for this is that ECMAScript Team has decided that Symbol
s can be explicitly coerce but not implicitly.
For that reason String(s)
work perfectly and prints out the string 'Symbol(Hello World)'
but the expression s + ''
throws an error.
parseInt('15') // 15
parseInt('15 and more') // 15
parseInt('more and 15') // NaN
By definition parseInt
converts its first argument to a string and then returns an integer or NaN
.
The problem here are the characters that do not represent a valid number in the specified radix
(by default is 10
). In our first example 15
, both 1
and 5
are valid numbers on base 10
, therefore the execution of parseInt
works smoothly and the integer 15
is returned.
However, "if parseInt
encounters a character that is not a numeral in the specified radix, it ignores it and all succeeding characters and returns the integer value parsed up to that point." This explains why our last example resolves into NaN
, meaning that when the engine encounters the first character that is not a numeral, i.e. m
, there's no integer value parsed until then.
(!+[]+[]+![]).length // 9
This is just a JS trick that involves some precedence
and coercion
.
To understand this we need to break it down:
- The first operation to happen is the logical NOT
!
on the unary plus+[]
, i.e.!+[]
.- Our unary operation
+[]
evaluates the operand[]
and converts it to a number, which results into0
. This0
is actually the conversion of the empty array[]
into the string''
and then into the number0
. - Next, our logical NOT
!
will negate the truthy of0
, which is first converted to the booleanfalse
. - In short,
!+[]
>!+''
>!+0
>!0
>!false
>true
.
- Our unary operation
- At this stage our expression is translated into
(true+[]+![]).length
, and the follow operation to take place istrue+[]
.- This time our
+
operator works as a concatenation operator evaluating first the operandtrue
. By specificationtrue
is converted into the string'true'
(this happens because the second operand when coerce results into a string). - We now evaluate our second operand
[]
, which is translated into the empty string''
. - In short,
true+[]
>'true'+[]
>'true'+''
>'true'
.
- This time our
- Our expression is now
('true'+![]).length
. Next we evaluate'true'+![]
.- Our first operand
'true'
is ready to be concatenated. - Our second operand
![]
needs to be evaluated and converted to a string. Therefore,!
negates the truthy of[]
, which by definition isfalse
, resulting into the stringfalse
. - In short,
'true'+![]
>'true'+false
>'true'+'false'
>'truefalse'
.
- Our first operand
- With our final expression being
'truefalse'.length
is easy to understand our result of9
.