前言
JavaScript中类型转换是一个很令人头疼的问题,特别是对于初学者来说。这是由于 JavaScript 是一种弱类型语言,它在运行时会尝试自动转换数据类型,以使表达式能够执行。这种灵活性使得 JavaScript 非常强大,但也容易引发一些不直观的行为。就比如当字符串与数字相加时,例如"3" + 2,JavaScript 将数字 2 隐式转换为字符串,而不是执行数学运算。今天我们就来聊聊JS中的类型转换规则,并且带你解决经典面试问题[ ] == ![ ] ?。
在前面三篇文章中,我们详细的介绍了原始数据类型之间的互相转换,以及对象类型转原始数据类型,接下来我们来聊聊什么时候会用到类型转换以及这道面试题该怎么解
首先我们先来看两道例题,我们将对象转换为原始数据类型,运用我们上篇所讲知识,看看会输出什么:
console.log(Number({})); // NaN console.log(Number([])); // 0
- 首先我们先来看看将空对象
{}
转化为Number
型的,我们可以看到答案为NaN
,我们来分析一下,我们在对对象进行类型转换时,JS引擎会进行两个操作,ToPrimitive({}, Number)
,第一步,我们先来看看{}
是不是基本类型,很显然不是,它是一个对象数据类型;接下来,我们调用valueof
方法,我们知道valueof
只能将包装类
转换为它们对应的原始值,{}
也不是包装类,所以我们不能得到原始值。接下来我们进行第三步,调用toString
方法,{}
空对象调用toString
方法得到'[object Object]'
,得到一个字符串类型的原始值。第一个操作结束 - 接下来进行第二个操作,将得到的原始值转化为对应的
Number
类型的值,因为原始值为'[object Object]'
,所以转化为数字类型时得到NaN
- 接下来我们来看看将
空数组[]
转化为Number
型的,我们知道数组也是对象,这里得到的答案为0
,首先引擎先进行第一个操作,ToPrimitive([], Number)
,第一步,我们先来看看[]
是不是基本类型,很显然不是,它是一个对象数据类型;接下来,我们调用valueof
方法,我们知道valueof
只能将包装类
转换为它们对应的原始值,[]
也不是包装类,所以我们不能得到原始值。接下来我们进行第三步,调用toString
方法,[]
空数组调用toString
方法得到''
,空字符串是一个字符串的原始值。第一个操作结束 - 我们进行第二个操作,将得到的原始值
''
转化为对应的Number
类型的值,所以空字符串在转化后得到0
一元运算符 +
在JavaScript中,一元运算符+
可以用于将值转换为数字类型。这个操作符会尝试将其后面的操作数转换为一个数字。我们来看几个例子:
console.log(+'1') // 相当于Number('1') 输出 1
当+号
后面跟一个东西时,JS引擎会将它转换为Number
类型,所以将字符串'1'
转化为数字1
, 所以输出1
.
console.log(+[]) // 0
这里就相当于我们上面所讲的,+[ ] 相当于 Number([])
,先调用ToPrimitive([], Number)
,得到原始值''
,最后得到0
console.log(+ {}) // NaN
这里就相当于我们上面所讲的,+{} 相当于 Number({})
,先调用ToPrimitive({}, Number)
,{}
空对象调用toString
方法得到'[object Object]'
,得到一个字符串类型的原始值。接下来进行数字类型转换,得到NaN
,所以最后输出NaN
console.log(+ [1, 2, 3]) // NaN
console.log(+ [1, 2, 3])
相当于Number(+ [1, 2, 3])
,先调用ToPrimitive(obj, Number)
,因为不是包装类,调用valueof
并不能得到原始值,所以调用toString
方法,得到'1,2,3'
字符串,然后将字符串转化为Number
类型,最后得到NaN
。
二元运算符 +
lprim + rprim == Toprimitive(v1) + Toprimitive(v2)
1. 转换之后当+两边有一个是字符串, 则按字符串进行拼接
2. 否则, 转到 number 进行计算
当Toprimitive(v1)
,v1为原始数据类型时,那么直接返回该值
例如:
console.log(1 + '1'); // '11'
Toprimitive(v1) + Toprimitive(v2)
之后,得到1 +'1'
,发现 +号
两边有一边为字符串类型,那么则进行字符串拼接看i,先将1
转为为字符串类型得到'1'
,最后拼接得到'11'
。
console.log(1 + null); // 1
Toprimitive(v1) + Toprimitive(v2)
之后,得到1 + null
,发现两边没有任何字符串,则转换到数字类型Number
进行计算,将null
转换为Number
,得到0
,所以最后输出 1 + 0 = 1
console.log([] + []); // ""
Toprimitive(v1) + Toprimitive(v2)
之后,得到'' + ''
,发现两边都为字符串,则将两个空字符串进行拼接,最后得到''
。
console.log([] + {}); // '[object Object]'
Toprimitive(v1) + Toprimitive(v2)
之后,得到'' + '[object Object]'
,发现+号
两边都为字符串,所以将它们两个进行拼接,最后得到'[object Object]'
经典面试题
[ ] == ![ ] ?
在JavaScript中,[ ] == ![ ]
表达式的结果是 true
让我们解释一下:
[ ]
是一个数组,它被视为一个对象。当使用相等运算符(==)比较两个对象时,JavaScript 将尝试将它们转换为相同的类型。![ ]
中的!
是逻辑非运算符,它将数组[ ]
转换为布尔值并取其相反值。由于数组被视为一个真值,![ ]
将为false
。- 然后,比较
==
进行的是类型转换后的值。在比较对象时,JavaScript 会尝试将它们转换为原始值。对于数组,转换后的原始值是一个空字符串。
因此,实际上,表达式 [ ] == ![ ]
转化为 "" == false
,之后会将它们转化为Number
类型,也就是0 == 0
,因此整个表达式的结果是 true
。
我们来看看伪代码:
[] == ![] true [] == !true [] == false '' == 0 0 == 0
总结
一元运算符+
在JavaScript中,一元运算符+
可以用于将值转换为数字类型。这个操作符会尝试将其后面的操作数转换为一个数字。
二元运算符+
lprim + rprim == Toprimitive(v1) + Toprimitive(v2)
1. 转换之后当+两边有一个是字符串, 则按字符串进行拼接
2. 否则, 转到 number 进行计算