const obj = { toString(){ console.log('调用了toString'); return {}; }, valueOf(){ console.log('调用了valueOf'); return {}; } } console.log(String(obj)); 控制台输出结果: >>>>>>>>>>>>>>>>>> 调用了toString 调用了valueOf Uncaught TypeError: Cannot convert object to primitive value
我们又发现:
在ToString情况下,如果toString和valueOf返回的都不是原始数据类型,那么js会抛出异常,提示无法将引用类型转换原始数据类型。
我们将三个结论综合一下:
在ToString情况下,js会优先调用toString,如果toString返回的不是原始数据类型,则会接着调用valueOf,如果valueOf返回的也不是原始数据类型,js会抛出一个异常,提示无法将引用类型转换原始数据类型。
具体流程图如下:
“==”下的valueOf和toString的优先级
从文章前面我们总结出来“==”的比较流程来看,引用类型转换成原始数据类型之后,如果是Sting类型的话,还要再次转成Number类型,因此“==”下的引用类型转换原始数据类型过程中,遵循ToNumber的优先级规则。
const obj = { toString(){ console.log('调用了toString'); return 'Hello,Teacher Cang!'; }, valueOf(){ console.log('调用了valueOf'); return 12345; } } console.log(obj==12345); 控制台输出结果: >>>>>>>>>>>>>>>>>> 调用了valueOf true
const obj = { toString(){ console.log('调用了toString'); return 12345; }, valueOf(){ console.log('调用了valueOf'); return {}; } } console.log(obj==12345); 控制台输出结果: >>>>>>>>>>>>>>>>>> 调用了valueOf 调用了toString true
const obj = { toString(){ console.log('调用了toString'); return {}; }, valueOf(){ console.log('调用了valueOf'); return {}; } } console.log(obj==12345); 控制台输出结果: >>>>>>>>>>>>>>>>>> 调用了toString 调用了valueOf Uncaught TypeError: Cannot convert object to primitive value
“==”之外的类型转换
“==”号只涉及到了ToPrimitive和ToNumber这两种转换,ToBoolean和ToString这两个没有涉及到的我们也介绍一下。
ToBoolean
对于ToBoolean,我们只需要记住几个特例是转成false的,其余的皆为true。
Boolean('') => false Boolean(undefined) => false Boolean(null) => false Boolean(0) => false
ToString
Number to String
Number转String之前,首先会做一个去0和补0的操作,然后再去转成String类型。
String(1.234) => "1.234" String(NaN) => "NaN" String(.1234) => "0.1234" String(1.23400) => "1.234"
Boolean to String
String(true) => "true" String(false) => "false"
null和undefined to String
String(null) => "null" String(undefined) => "undefined"
引用类型 to String
引用类型先ToPrimitive转换成原始数据类型,若转换后的原始数据类型不是String类型,再做String类型的转换。
const obj = { toString(){ console.log('调用了toString'); return true; } } console.log(String(obj)) 控制台输出结果: >>>>>>>>>>>>>>>>>> 调用了toString "true"
总结
“==”下的类型转换,要分为两种情况来考虑。第一种,原始数据类型;第二种,引用类型。原始数据类型中String类型和Boolean类型是需要转换成Number类型再去比较的,而引用类型则需要先转换成原始数据类型再进行后续的转换。搞清整个流程之后,我们再去理解“==”涉及到的ToNumber和ToPrimitive是如何进行转换的。按照这样子的理解步骤走,我们对“==”隐藏下的类型转换会有比较清晰的认识。另外,“==”不涉及到ToString和ToBoolean的类型转换,在文章的后面部分我也加上去了,希望可以给小伙伴们一个更加全面的类型转换的认识。最后附上完整的“==”类型转换的流程图: