烦人的强制类型转换

强制类型转换

强制类型转换在流程判断和部分代码不规范的相等运算符中应用比较多,至于为什么说代码不规范,我们后面会说到。
强制类型转换会让一些JavaScript初学者摸不着头脑,但是掌握其中的转换规则之后,就能轻松应对了。

流程判断

1
2
3
4
if(''){
console.log('true')
}
//undefined
1
2
3
4
if(' '){
console.log('true')
}
//true

上面两段代码中返回值一个是undefined,一个是true,看起来会摸不着头脑,两段代码的区别之处在于流程判断时一个是空字符串,一个是空格字符串。
在流程判断中,条件部分的值会被强制转换为布尔值,系统内部会自动调用Boolean函数。
所以上面例子中空字符串会被转化为false,空格字符串被转化为true,下面是转化规则,除了下面几种情况外,都为true:
(x代表条件部分的值)

x转换值
nullfalse
undefinedfalse
‘’(空字符串)false
0/+0/-0false
NaNfalse

另:
下面两种写法,有时也用于将一个表达式转为布尔值。它们内部调用的也是Boolean函数。

1
2
x ? true : false
!! x

相等运算符

相等运算符用于比较两个值,然后返回一个布尔值,表示是否相等。
在比较两个值是否相等时,相等运算符(==)比较两个值是否相等,严格相等运算符(===)比较它们是否为“同一个值”。
如果两个值不是同一类型,严格相等运算符(===)直接返回false,而相等运算符(==)会将它们转化成同一个类型,再用严格相等运算符进行比较。

看下面代码:

1
2
3
4
5
6
7
8
9
console.log(''==false) //true
console.log('0'==false) //true
console.log(' '==false) //true
console.log('true'==1) //false
console.log(true==1) //true
console.log([]==0) //true
console.log([1]==true) //true
console.log([1]=='1') //true
console.log({valueOf:function(){return 1}}==true) //true

看到结果是不是一脸懵逼?这里代码看起来违反直觉。
这里强制转换规则确实有点复杂,但是还是有规则可循的:

1.原始类型的数据间的比较

string、boolean、number数据之间比较的话,会先转换成数值类型之后再进行比较。

1
2
3
4
console.log(''==false) //true
//等同于Number('') == 0,即0 == 0
console.log('true'==1) //false
//等同于Number('true') == 1,即NaN == 0

2.原始类型和对象之间的比较

这里的对象指的是广义的对象,包括数组和函数等。
对象与原始类型的值比较时,先转化成原始类型的值,再进行比较。
其中,对象转换为原始类型值转换规则比较复杂,如下:

  • 1.调用对象自身的valueOf方法。如果返回原始类型的值,则直接对该值使用Number函数,不再进行后续步骤。
  • 2.如果valueOf方法返回的还是对象,则改为调用对象自身的toString方法。如果toString方法返回原始类型的值,则对该值使用Number函数,不再进行后续步骤。
  • 3.如果toString方法返回的是对象,就报错。

以下面代码为例:

1
2
3
var a = {a:1}
console.log(a==1) //false
//首先调用a.valueOf方法, 结果返回对象本身;于是调用a.toString方法,返回字符串[object Object],调用Number('[object Object]')

1
2
3
var b = [1]
console.log(b==1) //true
//首先调用b.valueOf方法, 结果返回对象本身;于是调用b.toString方法,返回字符串'1',调用Number('1')
1
2
3
4
5
6
7
8
9
10
var c = {
valueOf: function () {
return 1;
},
toString: function () {
return 0;
}
}
console.log(c==false) //false
//调用c.valueOf方法先于调用c.toString方法,所以返回1,调用Number(1)
1
2
3
4
5
6
7
8
9
10
var d = {
valueOf: function () {
return {};
},
toString: function () {
return {};
}
}
console.log(d==false) //报错
//首先调用d.valueOf方法, 结果返回对象{};于是调用d.toString方法,返回{},toString方法返回的不是原始类型的值,结果就会报错
3.undefined和null

这两个是特殊值,他们的比较结果也是特殊的。
undefined和null与其他类型的值比较时,结果都为false,它们互相比较时结果为true。

综上,JavaScript的相等运算符(==)是挺复杂的,也是很容易出错的。
因此为了写出更规范的代码,避免意外,建议大家不要使用相等运算符(==),最好只使用严格相等运算符(===)

0%