今天我们讲一讲js里面的类型转换
首先思考一个问题,为什么 '1' === 1会返回false,而 '1' == 1会返回true呢?
'1' === 1
// false
'1' == 1
// true
原来在js中“===”表示全等,并不会进行隐式转换,它只负责判断值和类型是否相等;而“==”会进行隐式转换,只判断值是否相等。
转换分为隐式转换和显式转换。我们先来讲一讲显示转换。
一、显示类型转换
1.原始类型转换
(1)转布尔
在js中我们可以通过Boolean()将其他类型转为布尔类型。
console.log(Boolean()); // false
console.log(Boolean(null)); // false
console.log(Boolean(undefined)); // false
console.log(Boolean(-100)); // true
console.log(Boolean(0)); // false
console.log(Boolean(NaN)); // false
console.log(Boolean('')); // false
console.log(Boolean('aaa')); // true
console.log(Boolean(true)); // true
根据例子可以发现:
对于null,undefined返回false,
对于数字,0和NaN返回false,其余数字则返回true,
对于字符串,空字符串返回false,其余则返回true。
(2)转数字类型
在js中我们可以通过Number()将其他类型转为数字类型。
console.log(Number(true)); // 1
console.log(Number(false)); // 0
console.log(Number(null)); // 0
console.log(Number(undefined)); // NaN
console.log(Number('')); // 0
console.log(Number('123')); // 123
console.log(Number('1,2,3')); // NaN
console.log(Number('abc')); // NaN
根据例子可以发现:
对于null返回0,undefined返回NaN,
对于布尔类型,true返回1,false返回0,
对于字符串,空字符串返回0,对于可解析的数值返回其解析数值,对于含有无法解析值的字母和逗号等则返回NaN。
(3)转字符串
在js中我们可以通过String()将其他类型转为字符串类型。
console.log(String(undefined)); // 'undefined'
console.log(String(true)); // 'true'
console.log(String(false)); // 'false'
console.log(String(123)); // '123'
根据例子可以发现,字符串的转换就比较简单粗暴,不论传入什么,直接加上引号转成字符串。
2.对象的类型转化
当我们在类型转换的时候传入的不是原始类型,而是对象,那么js又该怎么去处理呢?
我们可以查阅官方文档分析其底层逻辑。
根据官方文档我们可以知道,如果是对象转成字符串,js的运行逻辑:
首先js会先交给内置函数ToString({})去处理,之后再交给内置函数ToPrimitive()去处理。如果发现是想转成字符串,则执行Toprimitive({},String),处理完成返回结果给ToString()
如果如果是对象转成数字,js的运行逻辑:
js会先交给内置函数ToNumber({})去处理,,之后再交给内置函数ToPrimitive()去处理。如果发现是想转成字符串,则执行Toprimitive({},Number),处理完成返回结果给ToNumber()
那么Toprimitive()的运行逻辑又是什么呢?我们再分析一下官方文档。
(1)对象转成字符串String(obj) || Object.prototype.toString.(obj)
ToPrimitive(obj,String)
- 如果obj是原始类型,则直接返回
- 否则,调用obj.toString(),如果得到原始类型,则返回
- 否则,调用obj.valueOf(),如果得到原始类型,则返回
- 否则,报错
所以我们知道对象转字符串实际执行以下几种操作:
- {}.toString() 返回由 “[object”和class 和“]” 组成的字符串
- [].toString() 返回由数组中元素用逗号拼接组成的字符串
- xx.toString() 直接返回字符串字面量
(2)对象转数字:Number(obj) || Object.prototype.valueOf.(obj)
ToPrimitive(obj,Number)
- 如果obj是原始类型,则直接返回
- 否则,调用obj.valueOf(),如果得到原始类型,则返回
- 否则,调用obj.toString(),如果得到原始类型,则返回
- 否则,报错
此时得到的原始类型返回之后再进行原始类型转字符串。
(3)对象转布尔:Boolean(obj)
所以对象转布尔值都是true。
二、隐式类型转换
前面讲的都是隐式类型转换,接下来我们讲隐式类型转换发生的场景。
1.四则运算
包括 % ,/, * ,+ ,—
2.判断语句
if ,while ,== ,> ,< ,>= , <= , !=
3.一元运算符
加号+,转为数字
+‘123’ //123
4.二元运算符
val1 + val2
lprim = ToPrimitive(val1)
rprim = ToPrimitive(val2)
只要两边有字符串,那么两边统一转字符串,并拼接。
如果两边都是数字,则相加
两边转换会进行ToPrimitive()转化
5. ==
返回布尔类型
如果两边类型不一样,转number
null == undefined //true
具体原因我们参照官方文档
例题
学完之后我们来看一道题
[] == ![]
这个返回什么呢?我们来分析一下
左边:ToPrimitive([],Number) => [].toString() => ' ' => ' '.toNumber() => 0
右边:!优先级更高,所以先转布尔,Boolean([])为true。!true => false。Number(false) => 0
所以0 == 0 ,为真。