JavaScript是典型的弱类型语言,如果能很好理解类型转换特别是隐式转换时,比较强类型语言下它将变得非常有趣,比如在使用==
相等操作符时。
热身
为了更好展示弱类型,先来几个例子:
parseInt(0.0000004) //4
![] == [] //true
['x', 'y'] == 'x,y' //true
操作符
ECMA-262描述了一组用于操作数据值的操作符,包括算数操作符(如加号和减号)、位操作符、关系操作符和相等操作符,ECMAScript操作符的与众不同之处在于,它们能够适用于很多值,例如字符串、数字值、布尔值,甚至对象。不过,在应用于对象时,相应的操作符通常都会调用对象的valueOf()
和(或)toString()
方法,以便取得可以操作的值。
规则
String转换
var a = {
toString : function(){
console.log('调用了 a.toString');
return '111'
}
}
alert(a) //alert操作会调用a.toString方法
'qwe' + a //qwe111 同理
当toString不可用的时候,系统会再尝试valueOf方法
var a = {
toString : function(){
console.log('调用了 a.toString');
return {}
},
valueOf:function(){
console.log('调用了a.valueOf')
return {}
}
}
alert(a)
// 调用了a.toString
// 调用了a.valueOf
// Uncaught TypeErrpt: Cannot convert object to primitive value
Number转换
对象a+'edc'时会首先执行对象a的valueOf()方法
Boolean转换
值 | 布尔值 |
---|---|
true/false | true/false |
undefined, null | false |
Number |
0 ,NaN 对应false,其他的对应true |
String |
"" 对应false,其他对应true('0' 对应的是true) |
Object | true |
相等操作符
使用相等操作符会先转换操作数(通常称为强制转型),然后再比较它们的相等性。
在转换不同的数据类型时,相等和不相等操作符遵循下列基本规则
- 如果有一个操作数是
布尔值
,则在比较相等性之前先将其转换为数值————false
转换为0
,而true
转换为1
; - 如果一个操作数是
字符串
,另一个操作数是数值
,在比较相等性之前先将字符串转换为数值; - 如果一个操作数是
对象
,另一个操作数不是,则调用对象的valueOf()
方法,用得到的基本类型值按照前面的规则进行比较; - 如果两个操作数都是
对象
,则比较它们是不是同一个对象。如果两个操作数都指向同一个对象,则true
表达式 | 值 | 表达式 | 值 | |
---|---|---|---|---|
null == undefined | true | false == 0 | true | |
"NaN" == NaN | false | true == 1 | true | |
5 == NaN | false | true == 2 | false | |
NaN != NaN | true | undefined == 0 | false | |
"5" == 5 | true | null == 0 | false |
由于相等和不相等操作符存在类型转换问题,而为了保持代码中数据类型的完整性,我们推荐使用全等和不全等操作符。
解析[] == ![] 返回true
- 首先第一步右边的是逻辑判断
![]
,所以先转成boolean
[] == !true
[] == false
- 左边不是原始类型,尝试把左边转成原始类型,变成
' ' == false
- 最终都转换成
number
-
0 == 0
所以返回true
其他技巧
-
num1+''
number转为string -
~~double1
转为整数 -
1*str1
string转number -
!!sth
相当于Boolean(sth)
拓展题
[] == []
[] === []
{} == {}
{} === {}
NaN == NaN
NaN === NaN
小技巧:诸如{}
,[]
都是对象,只要它们不是指向同一个对象,无论==
还是===
都为false。另外,[]
的原始值为0,[42]
的原始值为42,[x,y]
的原始值为'x,y'
参考
- [1] JavaScript高级程序设计(第3版)[M]. p52
- [2] JavaScript 对象转换之 toString 和 valueOf
- [3] 你所忽略的js隐式转换(含ToPrimitive()介绍)