吐下槽,javascript数据类型真的很奇葩
看了一个页面《出几道JS的题》,当时确实挺感兴趣地就点进去了。但是看了那几道题,确实才感觉自己对javascript这个语言认识的缺乏。
{} + [] = ?
[] + 0 = ?
{} + 0 = ?
({} + []) = ?
之前看了《javascript高级程序设计》介绍数据类型的时候,知道在操作符的时候javascript的数据类型会出现转换在二元操作符"+"加法时,它会遵循一些规则:
-
1 两个操作符都是数值,就执行常规的加法运算
2 两个中有一个操作数是字符串
- (1)两个操作数都是字符串,就把两个拼接起来
- (2)其中有一个是字符串,那么就讲另外一个操作数转换成字符串,然后再拼接 3 有一个操作数是对象、数值或布尔值,就调用它们的toString()转换成字符串,而对于undefined和null就调用String()函数
- {} + [] =0
- [] + 0 = "0"
- {} + 0 = 0
- ({} + []) =[object Object]
出现上面结果的原因
-
对于javascript解析器,我们要了解下
- 第一个就是{}符号的使用,如果是通过var 来定义一个变量并把{}赋值给那个变量的话,那么它就是相当于new Object()。但是如果直接在js文件中使用{},javascript解析器会把它当成语句块(虽然js是没有块级作用域的)来使用,它已经不是对象的意思了。
-
第二个是一元操作符“+”的使用,它对数据类型的转换是相当于调用Number()构造函数的,它也有一系列的规则
- Boolean类型,true和false会分别被转换成1,0
- null转换成0,undefined转换成NaN
- 字符串类型,转换比较复杂。
(1) 如果都是数字,就将其转换成十进制,并会忽略掉前导的零
(2) 如果包含有效的小数点的话,它会转换成浮点类型
(3) 如果包含有效的16进制的话, 会转换成10进制
(4) 如果是空字符串的话,就转换成0
(5) 其余的转换成NaN
- 如果是对象的话
(1) 先调用对象自身的valueOf方法,如果该方法返回原始类型的值(数值、字符串和布尔值),则直接对该值使用Number方法,不再进行后续步骤;
(2) 如果valueOf方法返回复合类型的值,再调用对象自身的toString方法,如果toString方法返回原始类型的值,则对该值使用Number方法,不再进行后续步骤;
(3) 如果toString方法返回的是复合类型的值,则报错
-
{} + [] = ?
- 结果:0
- 原因:js解析器把最前面的{}当成语句块来执行,所以其实{}+[]就相当于执行+[] 而+[]相当与执行Number([]),它先调用[].valueOf()查看下还是返回原数组(复合元素),所以执行[].toString()得到了""表示空字符串,所以Number([])相当于执行Number(""),最后得到的是0。 [] + 0 = ?
- 结果:"0"
- 原因:我们知道[]会执行[].toString()变成“”,注意现在已经变成字符串连接了,二元操作符+变成了字符串连接符,所以会把数值的0变成字符串“0”,然后再跟“”连接 {} + 0 = ?
- 结果:0
- 原因:同第一个{}+[] ({} + []) = ?
- 结果:"[object Object]"
- 原因:()有一种语义是强制表达式运算,所以现在的{}是不能看成语句块的,只能是对象,所以{}.toString执行完就是[object Object],在加上[].toString()为“”,所以就是"[object Object]"
参考文献
Javascript小括号“()”的多义性数据类型转换(阮一峰好文章)