关于数据类型转换的面试题总结

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都要先进行隐式强制类型转换,再做“加”运算。

  • 当“+”符号两端存在一个或两个不是数字类型的值时,需要把“+”符号两端都先进行“取原始值”操作(ToPrimitive)。
  • a和b都是数组类型,要进行取原始值操作的话,解析器会对数组先调用valueOf()方法,如果有该方法并且返回值是原始类型的话就是这个返回值;否则继续调用toString()方法,如果返回的是原始值,则利用这个返回值进行“加”运算;否则会抛出异常
  • 那么对于这个例子来说,[1,2]和[3,4]最终会调用toString()方法,分别返回字符串"1,2"和"3,4",再进行“加”运算后,结果就是"1,23,4"

2.代码 []+{} 和 {} + [] 输出的结果又什么不同?解释其原理。

结果如下:

  • "[object Object]"
  • 0

原理:

上面的问题涉及到JavaScript语法解析,所以不要把上面问题中的表达式以参数形式传递到console.log()alert()方法中进行试验,那样你得到的结果会不一样。

先说[]+{}

这里会与第一题很相似,都会去取原始值,左侧的数组结果为空字符串——"",右侧的空Object的结果为字符串——"[object Object]",那么再进行加运算的话,就是字符串拼接,最终结果为"[object Object]"

再说{}+[]

这里有些意外,因为涉及到了JavaScript的语法解析规则。在这段代码中,解析器遇到{}后将其解析为了一个空的代码块,而又将"+[]"解析为对于空数组的一元操作“+”,也就是将数组强制转换为数字,而空数组转换为数字的话就是0,那么最后结果自然就是0了。

3.说说什么是 显式强制类型转换 和 隐式强制类型转换?谈谈你对于二者的看法

显式强制类型转换是通过显而易见的、目的明确的代码将数据进行强制类型转换,如Number()就是将变量显式的强制转换为数字类型的值。

隐式强制类型转换往往是一些操作的附带产物,如if(){}中会将括号内的部分转换为布尔类型。

而关于”显式“和”隐式“是很主观的,如果+”123“对你来说,你一眼就能看出这是将字符串”123“转换为数字的操作,那么这对于你来说就是显式的强制类型转换。

4.将一个变量强制转换为字符串,你能说几种方法?

  • 使用String() ——String(123)
  • 直接调用toString()方法——var a = 123;a.toString();
  • 使用JSON.stringify()方法——JSON.stringify()
  • 利用字符串拼接——123+""

其中第一种最为稳妥。

第二种的缺点是,如果对象修改了自身的toString()方法的话,会影响到最终结果

第三种的缺点是,缺点还是很多的……,如果传入的参数本身就是字符串的话,返回的结果是带双引号的,如下面:

如果传入的是Object还要确保没有递归引用,否则会抛出异常,如下面

MDN还给出了下面的注意提醒:

关于序列化,有下面五点注意事项:

  • 非数组对象的属性不能保证以特定的顺序出现在序列化后的字符串中。
  • 布尔值、数字、字符串的包装对象在序列化过程中会自动转换成对应的原始值。
  • undefined、任意的函数以及 symbol 值,在序列化过程中会被忽略(出现在非数组对象的属性值中时)或者被转换成 null(出现在数组中时)。
  • 所有以 symbol 为属性键的属性都会被完全忽略掉,即便 replacer 参数中强制指定包含了它们。
  • 不可枚举的属性会被忽略

第四种的缺点是,表面上看上去应该和第一种String()是一样的,但是其实还是有些差距的,下一题咱们再讨论。

5.通常的两种转字符串的方法: String(a) 和 a+""。他们之间是否存在差异?

两者看上去都是将变量转换为字符串,但是还是有个细微差别的。

看下面的例子:

通过现象可以看得出来,String()是直接调用了a的toString()方法,而a+""则是先调用了valueOf()方法。原因是加运算是隐式强制类型转换,会对两端操作数进行ToPrimitive操作,前面已经说过,这里不再赘述。

这里有个经典的例子,就是在ES6下对于Symbol类型值进行字符串转换时。

6.有哪些值强制转换成布尔类型时结果为false?

此题必考!

  • undefined
  • null
  • -0
  • +0
  • NaN
  • false
  • ""

此外还有一种是假值对象,注意下面的代码(在Chrome中运行)

7. 宽松相等——“==”和严格相等——“===”有什么区别?

很多人会说——“==检查值是否相等,===检查值和类型是否相等”,

正解应该是——“==允许在相等比较中进行强制类型转换,而===不允许”。

8.下面的代码输出是什么?解释其原理。

结果输出false

还是会有一部分人会犯这个错误的,因为下面的代码我们经常会使用:

大家觉得"666"转换为布尔类型应该是true啊,所以上面的a==b应该是true。但其实并不是这样,关于宽松相等==来说逻辑十分复杂且晦涩难懂,难以记忆。

这里我觉得答出是 false就可以了,因为有下面这个公式要记忆

MDN对于宽松相等的表格总结

可以看出,==两端是布尔类型和字符串类型的时候,会对两端都进行ToNumber操作,也就是"666"被转换为数字666,而true被传唤为1,所以最终结果自然为false。

说到这里,既然宽松相等的强制类型转换这么晦涩难懂而且不好记忆,那么我们应该怎么办?

给大家几个建议:

  • 如果==两端有true或false,那么千万不要使用==
  • 如果==两端的值中有[]、""、或者0,尽量不要使用==

9.什么样的处理可以使得下面的代码输出为true?

实际上我的处理是这样的(此题是我在《你不知道的JavaScript中卷》中看到的):

此例重点是想提醒大家,每次的类型转换都会调用变量的valueOf()方法,应该尽量知道自己在做什么,才可以做类似这样的比较操作。

10.将一个变量强制转换为数字类型时,都进行了哪些操作?

将变量强制转换为数字遵循的是ToNumber操作。

对于基本类型的话:

  • true → 1
  • false → 0
  • undefined → NaN
  • null → 0
  • 对于字符串,遵循常量的相关规则语法,如果转化失败就返回NaN

对于对象来说:

会先进行去原始值操作ToPrimitive,即先检查该值是否有valueOf()方法,如果有并且返回的基本类型值,就使用该值进行转强制类型转换。如果不是就使用toString()的返回值进行强制类型转换。如果valueOf()和toString()均不返回基本类型值,会产生TypeError错误。

原文发布于微信公众号 - 较真的前端(gh_7af41a2be77e)

原文发表时间:2017-11-22

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏软件开发 -- 分享 互助 成长

为什么构造函数不能为虚函数

1、从使用角度         虚函数主要用于在信息不全的情况下,能使重载的函数得到对应的调用。构造函数本身就是要初始化实例,那使用虚函数也没有实际意义呀。所以...

23090
来自专栏用户3030674的专栏

java接口

接口中常量的修饰关键字:public,static,final(常量) 函数的修饰关键字:public,abstract 如果没有写全,系统在编译时会自动加上 ...

15520
来自专栏静默虚空的博客

[Java 基础]控制语句

选择语句 if语句 if语句会判断括号中的条件是否成立,如果成立则执行if语句中的代码块,否则跳过代码块继续执行。 语法 if(布尔表达式) { //如果布尔...

21560
来自专栏程序员互动联盟

【编程基础】Java的八种基本数据类型

程序=数据+算法,也就是说程序就是你编写算法操作数据。Java是一种强类型语言,也就是说每一个变量都必须是某种类型的变量。在Java中数据类型分为基本数据类型和...

38880
来自专栏程序员互动联盟

【专业技术】关于JS的prototype

概述: 在接触JS的过程中,随着理解的深入会逐渐的理解一些比较深奥的理论或者知识,那么今天我们来介绍一下比较难理解的prototype和constructor。...

34860
来自专栏Python

dict中items和iteritems的区别

字典items()方法和iteritems()方法,是python字典的内建函数,分别会返回Python列表和迭代器,下面一起来看下字典items()和iter...

40170
来自专栏锦小年的博客

python学习笔记2.3- 循环、判断

会了print()以后就可以开始基础编程,首先要学会怎么表达循环和条件判断,这是程序中用来表达逻辑的语法。python中的循环关键字有:for 和 while...

194100
来自专栏编程

Python函数之形参与实参

各位小伙伴,大家晚上好 今天我们来一起探讨一下函数的另外一个重要概念 “形参”(xing2,can1)与“实参”(shi2,can1) 很多朋友可能第一次听到这...

35680
来自专栏菩提树下的杨过

ruby学习笔记(6)-Array的使用

ruby的数组基本使用,跟c#中的数组比起来,最不习惯的区别在于允许负索引(跟javascript到有几分相似) arr=[3,4,5,6,7,8,9] pu...

20450
来自专栏GreenLeaves

C#运算符的优先级

在C#中,一共有38个常用的运用符,根据它们所执行运算的特点和它们的优先级,为了便于记忆,我将它们归为七个等级:1、单元运算符和括号。2、常规算术运算符。3、位...

229100

扫码关注云+社区

领取腾讯云代金券