那些年,面试遇到的关于JavaScript隐式转换的题

前言

不知道大家有没有见过这样的一张图?
JS搞笑图
我当时看见这张图的时候,表情和他几乎一样,内心毫无波澜甚至想笑。。。我还仔细看了看,发现有些地方貌似还真不咋清楚,于是我又来复习了一遍关于JavaScript的隐式转换。。。

隐式转换

首先要清楚JavaScript中存在两个方法valueOftoString,他们存在于最顶层的原型Object.prototype上,也就是说我们可以通过原型链访问到这两个方法,他们是用于ToPrimitive也就是转换为原始值。valueOf函数返回的是本身(基础类型则是原始值,引用类型则是this);toString函数在基础类型中返回的是字符串化的原始值,在引用类型中则是返回的当前类型。值得注意的是,JavaScript中的内置对象对valueOftoString进行了不同的实现。

说到这里就要说一下另一个概念:原始值。原始值又是啥呢,其实就是我们经常说的基础数据类型。

在进行隐式转换时,总是会先调用valueOf,如果返回值不值原始值的话,又会继续调用toString方法(Date类型例外,它是默认先调用toString,然后再调用valueOf)。对于非引用类型,valueOf返回的则是原始值,引用类型则是返回的它本身。举个栗子:

const obj = {
	valueOf() {
		return 'valueOf';
	},
	toString() {
		return 'toString';
	}
};

console.log(obj + ''); // valueOf

部分内置的对象实现的valueOf和toString方法一览如下:

类型(栗子)valueOftoString
Number(123)123‘123’
String(‘ab123’)‘ab123’‘ab123’
Boolean(‘666’)true‘true’
Date()时间戳日期字符串
Array([1, 2, 3])this‘1,2,3’(相当于调用join(',')
Object({})this‘[object Object]’
Function(() => {})this‘() => {}’
RegExp(‘1’)this‘/1/’

在JavaScript中的隐式转换无非就是涉及这几类:==运算符if语句。其中==运算符这两种涉及到的隐式转换无非就是两种,一种是转换为数字,一种是转换为字符串。

类型toNumbertoString
null0‘null’
string可以转换为数字的转换为数字,否则NaNstring
bool0、1‘true’ 、 ‘false’
numbernumber字符串形式的number
object先调用valueOf获取原始值,然后再toNumber先调用toString获取原始值,然后再转换成字符串

说了这么些似是而非的东西,估计还是非常懵,我们来解答一下最开始的那种图中的栗子来细细体会一下(不是隐式转换的内容就跳过了,还有注释才是关键~)。有点需要注意:+ 运算符即可以表示字符串的连接符,又可以表示加运算,在+的两端如果存在一个字符串类型,则表示连接字符串,否则是数学运算。栗子:

[] + []

[] + [] = ?
// + 运算符即可以表示字符串的连接符,又可以表示加运算,在+的两端如果存在一个字符串类型,则表示连接字符串
// 上述代码可以分解成:
// a = ToPrimitive([]); b = ToPrimitive([]); a + b = ?
// ToPrimitive([])首先调用的是valueOf函数,返回本身,不是原始值,继续调用toString函数。根据上面的表格可以得到ToPrimitive([])=''
// 于是就变成了 '' + '' = ''

[] + {}

[] + {} = ?
// 有了上一题的经验,我们很快可以简化成这样的算式
// ToPrimitive([]) + ToPrimitive({}) = ?
// 根据上面的表格中的内容:'' + '[object Object]' = '[object Object]'

{} + []

{} + [] = ?
// 一看到这一题,可能会有童鞋抢答了,哎哟这一题我知道,和上面的一样 = '[object Object]'
// 当你将表达式输入devtool中时可能就会傻眼,{} + [] = 0??? what the fuck???
// 其实是浏览器把{}当成了一个代码块,所以{} + []实际上是 +[]
// 我们再来看看 +[],将[]装换为数字,为0
// {} + [] = 0

true + true + true

true + true + true = ?
// 因为全是原始值的缘故,所以true+true+true不变,而+两边都不存在字符串,所以true需要格式化成数字
// true + true + true => 1 + 1 + 1 = 3

图中其他的就不多说了,大致上差不多,接下来说说 ==的情况:
x == y同种类型直接比较,属于不同类型时:

  • x和y属于null, undefined则返回true
  • 存在bool类型,或者属于string、number时,转换为number进行比较
  • 存在引用类型时,将引用类型转换为原始值,然后再进行比较

看个栗子:
![] == []

![] == []
// 这个表达式在面试中出现的几率还是蛮高的,按照上面的方法来解读一下
// !的优先级高于=,则变成false == []
// 根据上述原则,[]会调用valueOf得到 '',表达式进一步转换为 false == ''
// 当存在一个bool类型时,转换为数字类型进行比较 false == '' => 0 == 0

需要注意的是undefined和它本身和null之外,并不与其他相等。

以上,就是隐式转换的一些简单的认识,希望对各位童鞋有所帮助。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值