数据类型的隐式转换
一、基本数据类型的转换
1.加减乘除
加法:如果字符串加数字,数字就会转成字符串。而 数字加数字 或 字符串加字符串 则不需要进行转换直接进行运算或字符串拼接。
减法: 数字减字符串,字符串转成数字。如果字符串不是纯数字就会转成NaN。字符串减数字也一样。两个字符串相减也先转成数字。
乘,除,大于,小于跟减法的转换一样。
双等号 == :
- undefined等于null
- 字符串和数字比较时,字符串转数字
- 数字和布尔比较时,布尔转数字
- 字符串和布尔比较时,两者转数字
// ==
undefined == null; //true
'0' == 0; //true,字符串转数字
0 == false; //true,布尔转数字
'0' == false; //true,两者转数字
二、引用数据类型的转换
引用类型和基本类型相对复杂一些,先要把引用类型转成基本类型,再按上述的方法比较。
通过ToPrimitive将值转换为原始值
js引擎内部的抽象操作ToPrimitive有着这样的签名:
ToPrimitive(input, PreferredType?)
input是输入的值,即要转换的对象,必选;
preferedType是期望转换的基本类型,他可以是字符串,也可以是数字。选填,默认为number;
他只是一个转换标志,转化后的结果并不一定是这个参数值的类型,但是转换结果一定是一个原始值(或者报错)。
对于Date求原始值比较特殊,PreferredType是String,其他Object对象均为Number。
既然要隐式转换,就应该有一套转换规则,才能追踪最终转换成了什么
隐式转换中主要涉及到三种转换:
1、将值转为原始值,ToPrimitive()。
2、将值转为数字,ToNumber()。
3、将值转为字符串,ToString()。
PreferredType转换策略
- 如果PreferredType被标记为Number,则会进行下面的操作流程来转换输入的值。
- 如果输入值已经是一个原始值,那么直接返回该值即可
- 如果输入值为一个对象,则调用该对象的 valueOf() 方法,若 valueOf() 返回的是原始值,则返回原始值
- 否则调用该对象的 toString() 方法,若 toString() 返回的是原始值,则返回原始值
- 否则抛出 TypeError 异常
如果PreferredType被标记为String,则会进行下面的操作流程来转换输入的值。
- 如果输入值已经是一个原始值,那么直接返回该值即可
- 否则调用该对象的 toString() 方法,若 toString() 返回的是原始值,则返回原始值
- 如果输入值为一个对象,则调用该对象的 valueOf() 方法,若 valueOf() 返回的是原始值,则返回原始值
- 否则抛出 TypeError 异常
注意点:
PreferredType的值会按照这样的规则来自动设置:
- 该对象为Date类型,则PreferredType被设置为String
- 否则,PreferredType被设置为Numbe
!数据类型转换重要案例!
*******
[] + [] // ""
解析:由于两个都是Array对象,不是Date对象,所以以Number作为转换标准,先调用valueOf() 方法,结果仍然为 [] ,不是原始值,所以我们继续调用 tostring() 方法,结果为一个"" (空字符串)原始值,将 "" (空字符串)返回。同理,第二个也返回一个 "" (空字符串),此时加号两边都为string 类型,直接进行字符串拼接,结果仍然为 "" (空字符串)。
*******
[] + {} // "[object Object]"
解析:
同上,[]的结果是"" (空字符串)
{} 先调用 valueOf() 方法,结果为{} ,不是原始值,继续调用 toString() ,结果为 [object Object] ,是原始值,返回该值。
由于两边结果都是string类型,进行字符串拼接,结果为[object Object]
*******
{} + [] // 0
在node中的结果与上一个相同:
在浏览器控制台打印结果为0:
解析:在js解释器中,开头的{}会被当作一个代码块,而非js对象,被解析时就成了一个空代码块,直接被略过,剩下一个[] 就成了一元运算,[]的原始值为 "",将其转化为Number结果为 0 .
*******
{} + {} // "[object Object][object Object]"
在node中结果符合预期:
在普通浏览器中会显示NaN :
解析:在node中会将以“{”开始,“}”结束的语句外面包裹一层( ),就变成了({ } + { }),结果就符合预期。而普通版本的chrome依然会解析成{};+{},结果就变成了NaN