JavaScript语言的数据类型转换一直被很多人诟病,认为他晦涩难懂,使得很多人对他敬而远之。 但其实如果你知道了其中的原理,数据类型转换不仅不会困扰到你,反而会让你的代码可读性大大增强。也因此对于数据类型转换的掌握程度成为了判断一个前端开发工程师是否为一个老司机的主要标准。
更多面试题可以点击阅读全文进入前端面试题汇总—知乎专栏
问题一览
1.下面的代码输出是什么?解释其原理。
2.代码 []+{} 和 {} + [] 输出的结果又什么不同?解释其原理。
3.说说什么是 显式强制类型转换 和 隐式强制类型转换?谈谈你对于二者的看法
4.将一个变量强制转换为字符串,你能说几种方法?
5.通常的两种转字符串的方法: String(a) 和 a+""。他们之间是否存在差异?
6.有哪些值强制转换成布尔类型时结果为false?
7. 宽松相等——“==”和严格相等——“===”有什么区别?
8.下面的代码输出是什么?解释其原理。
9.什么样的处理可以使得下面的代码输出为true?
10.将一个变量强制转换为数字类型时,都进行了哪些操作?
问题解答
1.下面的代码输出是什么?解释其原理。
输出结果是“1,23,4”
原理:
a + b运算操作中,a和b用“+”连接,使得a和b都要先进行隐式强制类型转换,再做“加”运算。
2.代码 []+{} 和 {} + [] 输出的结果又什么不同?解释其原理。
结果如下:
原理:
上面的问题涉及到JavaScript语法解析,所以不要把上面问题中的表达式以参数形式传递到console.log()或alert()方法中进行试验,那样你得到的结果会不一样。
先说[]+{}
这里会与第一题很相似,都会去取原始值,左侧的数组结果为空字符串——"",右侧的空Object的结果为字符串——"[object Object]",那么再进行加运算的话,就是字符串拼接,最终结果为"[object Object]"
再说{}+[]
这里有些意外,因为涉及到了JavaScript的语法解析规则。在这段代码中,解析器遇到{}后将其解析为了一个空的代码块,而又将"+[]"解析为对于空数组的一元操作“+”,也就是将数组强制转换为数字,而空数组转换为数字的话就是0,那么最后结果自然就是0了。
3.说说什么是 显式强制类型转换 和 隐式强制类型转换?谈谈你对于二者的看法
显式强制类型转换是通过显而易见的、目的明确的代码将数据进行强制类型转换,如Number()就是将变量显式的强制转换为数字类型的值。
隐式强制类型转换往往是一些操作的附带产物,如if(){}中会将括号内的部分转换为布尔类型。
而关于”显式“和”隐式“是很主观的,如果+”123“对你来说,你一眼就能看出这是将字符串”123“转换为数字的操作,那么这对于你来说就是显式的强制类型转换。
4.将一个变量强制转换为字符串,你能说几种方法?
其中第一种最为稳妥。
第二种的缺点是,如果对象修改了自身的toString()方法的话,会影响到最终结果
第三种的缺点是,缺点还是很多的……,如果传入的参数本身就是字符串的话,返回的结果是带双引号的,如下面:
如果传入的是Object还要确保没有递归引用,否则会抛出异常,如下面
MDN还给出了下面的注意提醒:
关于序列化,有下面五点注意事项:
第四种的缺点是,表面上看上去应该和第一种String()是一样的,但是其实还是有些差距的,下一题咱们再讨论。
5.通常的两种转字符串的方法: String(a) 和 a+""。他们之间是否存在差异?
两者看上去都是将变量转换为字符串,但是还是有个细微差别的。
看下面的例子:
通过现象可以看得出来,String()是直接调用了a的toString()方法,而a+""则是先调用了valueOf()方法。原因是加运算是隐式强制类型转换,会对两端操作数进行ToPrimitive操作,前面已经说过,这里不再赘述。
这里有个经典的例子,就是在ES6下对于Symbol类型值进行字符串转换时。
6.有哪些值强制转换成布尔类型时结果为false?
此题必考!
此外还有一种是假值对象,注意下面的代码(在Chrome中运行)
7. 宽松相等——“==”和严格相等——“===”有什么区别?
很多人会说——“==检查值是否相等,===检查值和类型是否相等”,
正解应该是——“==允许在相等比较中进行强制类型转换,而===不允许”。
8.下面的代码输出是什么?解释其原理。
结果输出false
还是会有一部分人会犯这个错误的,因为下面的代码我们经常会使用:
大家觉得"666"转换为布尔类型应该是true啊,所以上面的a==b应该是true。但其实并不是这样,关于宽松相等==来说逻辑十分复杂且晦涩难懂,难以记忆。
这里我觉得答出是 false就可以了,因为有下面这个公式要记忆
MDN对于宽松相等的表格总结
可以看出,==两端是布尔类型和字符串类型的时候,会对两端都进行ToNumber操作,也就是"666"被转换为数字666,而true被传唤为1,所以最终结果自然为false。
说到这里,既然宽松相等的强制类型转换这么晦涩难懂而且不好记忆,那么我们应该怎么办?
给大家几个建议:
9.什么样的处理可以使得下面的代码输出为true?
实际上我的处理是这样的(此题是我在《你不知道的JavaScript中卷》中看到的):
此例重点是想提醒大家,每次的类型转换都会调用变量的valueOf()方法,应该尽量知道自己在做什么,才可以做类似这样的比较操作。
10.将一个变量强制转换为数字类型时,都进行了哪些操作?
将变量强制转换为数字遵循的是ToNumber操作。
对于基本类型的话:
对于对象来说:
会先进行去原始值操作ToPrimitive,即先检查该值是否有valueOf()方法,如果有并且返回的基本类型值,就使用该值进行转强制类型转换。如果不是就使用toString()的返回值进行强制类型转换。如果valueOf()和toString()均不返回基本类型值,会产生TypeError错误。