Conversion, toString and valueOf
JS中有三种对象可以转换成原始数据类型
1.Numeric 2.String 3.Boolean
原始数据类型:
1.undefined/null
2.string
3.boolean
4.number
String: output, uses toString.
Numeric: maths, operators, uses valueOf -> toString.
Boolean: converts according to the table.
Value Converted to…
true/false no conversion
undefined, null false
Number 0, NaN become false, others - true.
String "" becomes false, any other - true
Object true
字符串转换发生在对象需要进行字符串表示时(output时)
toString for Objects outputs: [object Object]alert( [1,2] )
toString for Arrays lists elements "1,2"
toString for Dates outputs the date as a string
显示转换(String(obj))
可以自定义toString方法
Numeric conversion
数制转换主要发生在两种情况下:
- 需要数字的函数如Math,isNaN,parseInt 以及算数操作符时
- 在比较的时候(除了===)这个很重要的撒
首先 valueOf 如果返回原始数据类型,则返回 然后toString若返回原始数据类型则返回,否则抛出异常
显示转换 Number(obj)
Numeric 转换并不意味着一定会返回一个数字,只要返回原始数据类型就行。
Because of that, a good way to convert an object to a string is the binary addition:
var arr = [1,2,3]
alert( arr + '' )
// first tries arr.valueOf(), but arrays have no valueOf 【算术运算符‘+’】
// so arr.toString() is called and returns a list of elements: '1,2,3'
//但这仍然叫做numeric转换
Other mathematical functions not only perform the numeric conversion, but enforce a number. For example, the unary addition +arr would give NaN:
The default implementation of Array#toString lists it’s comma-delimited values:
Boolean context
There is one more standard conversion in JavaScript, called [[toBoolean]]
in the specification.
If happens in boolean context, like if(obj)
, while(obj)
etc.
Object may not implement such conversion on their own, there is no magic method. Instead, there is a hardcoded table of conversions:
Value | Converted to… |
---|---|
true/false | no conversion |
undefined , null | false |
Number | 0 , NaN become false , others - true . |
String | "" becomes false , any other - true |
Object | true |
Unlike many programming languages (for example PHP), "0"
is true
in JavaScript.
In the example below, we have numeric conversion (equality does it):
1 alert( [0] == 0 ) // true 2 alert( "\n0\n" == 0 ) // true 3 alert( "\n0\n" == false ) // true
So one may guess that [0]
and "\n0\n"
are falsy, because they equal 0
.
But now let’s see how the left part behaves in boolean context:
1 if ([0]) alert(1) // 1, if treats [0] as true
2 if ("\n0\n") alert(2) // 2, if treats "\n0\n" as true
It is possible that a == b
, but in boolean context a
is true
and b
is false
.
To convert a value to boolean, you may use double-negation: !!val
or direct callBoolean(val)
.
Of course, we never use new Boolean
for any purpose. Funny things happen if we do.
For example, let’s try to get a boolean out of zero:
alert( new Boolean(false) ) // false
But…
1 if ( new Boolean(false) ) {
2 alert(true) // true
3 }
That’s because new Boolean
is an object. The alert
converts it to String, and it becomes "false"
… Right.
But if
converts it to boolean primitive, and here any object is true… Wops!
Java programmers’ eyes usually pop out when they see that.
Why they are equal?
1 alert( [] == ![] ) // true
- First, the two sides of comparison are evaluated. The right side is
![]
. Logical NOT'!'
converts to boolean. According to the table, an object[]
istrue
. So, the right side becomes![] = !true = false
. It brings us to:
[] == false
- The equality check between an object and a primitive converts the object to primitives in numeric way.
The array has no
valueOf
, but hastoString
which converts it to a comma-delimited list of items. In our case, no items lead to an empty string:'' == false
- Comparison between different primitives converts them to numbers:
0 == 0
Now the result is obvious.