隐式类型转换以及类型判断的方式(有坑)
== 的隐式类型转换
1. 两边如果存在null或者undefined,他们只和对方以及自身相等,和其他的都不等
null == undefined // true
null == false // false
null == 0 // false
2. 如果等式两边有布尔类型,要将布尔类型转化成数字
3. 如果等式两边有数字,就要将不是数字的那边转化成数字
4. 如果等式两边有对象存在,就要调用对象的ToPrimitive方法,转换为原始类型,原理是先调用valueof转换为原始类型,但是如果不是原始类型,就调用toString方法
// 一些经典等式转换的分析
1. false == undefined
根据第一条直接返回false
2. false == null
根据第一条直接返回false
3. false == ""
根据第二条,false => 0
再根据第三条,将 "" => 0
所以返回true
4. false == []
根据第二条,false => 0
再根据第四条,将[] => ""
再根据第三条,将 "" => 0
4. ! [ ] == ''
!的优先级高于 == ,而且!是一个转化成布尔值再取反的含义
转化成布尔值
- 如果是数字,除了0和NaN,都转化为true
- 如果是字符串,除了空串,都转化为true
- 如果是对象,都转化为true
- 如果是null,undefined都转化为false
所以这里[ ] => true ![ ] => false => 0
'' => 0
所以结果是true
5. ![ ] == [ ]
通过4的分析,这个就变得很容易了
![ ] => false => 0
[ ] => "" => 0
所以最后返回true
6. !{} == {}
!{} => false => 0
根据第4条,{}转化成字符串,调用toString,返回值是"[object Object]"
根据第3条, "[object Object]" => NaN
所以最后返回false
7. 重新给{}封装一个toString方法,就可以使6相等
let obj = { toString() { return 0 } } console.log(obj == !obj) // true
在调用toString的时候,就返回0,就和false相等
8. 还有一个习惯性思维的坑,补一下
0.3 == true
开始直接就想0.3转化成布尔类型是true,所以这个返回值是true
但是记住,布尔值和数字作比较的时候是将布尔值转化为数字
true => 1
0.3 == 1 => false
9. false == '0'
false => 0
'0' => 0
因为==在判断相等的时候存在很多隐式类型转换,导致比较的结果不可预测。所以我们一般用===(强相等)。
但是强相等还是有一点小问题,对于NaN===NaN , -0 ====+0。都是得不到预期的值。
但是Object.is(a,b)是可以的
Object.is(NaN, NaN) = true
Object.is(-0, +0) = false
(后面再补其他形式的隐式类型转换)
类型判断的几种方法
首先在说类型判断之前先将Js的数据类型8种:Boolean,String,number,undefined,null,Symbol,Bigint,Object
数据类型知道了,还要知道js有内置对象,除了undefined和null,基本类型都是有包装类的
1. typeof
特殊的点:
typeof null = “object”
// 为什么null的类型判断是object?这是一个历史遗留的问题,typeof判断一个数据是object的原理是只要二进制数据是以000开头的,就认为是对象,但是Null转化成二进制是全0,所以就会被默认为是object
typeof function(){} = "function"
只能验证标准的数据类型
对于其他没有清晰的判断,一般都会判断为"object"
2. instanceof
A instanceof B 原理就是B是否在A原型链上
所以能判断自定义对象的类型,可以验证自定义对象之间的继承关系,可以判断内置对象,但是不能判断原始对象
"aa" instanceof String // false 包装类只在创建的一瞬间存在,之后就销毁了
[ ] instanceof Array // true // 因为这个是对象,存在原型链
3. constructor
也是原型链上的,可以找到原型的构造函数是什么
"aa".constructor == String // true
// 开始一直不明白为什么constructor为true,但是instanceof为false。原来是在constructor的时候,先将"aa"转化成了对象,然后再获取他的constructor的
因为instanceof是类型的判断,就不存在隐式类型转化,但是constructor是为了获取这个数据上面的这个属性,就会进行隐式类型转换
constructor也可以获取自定义类型的,但是null和undefined是不能转化为对象的,所以null/undefined.constructor是会报错的
4.Object.prototype.toString.call()
基本可以判断所有的数据类型,而且判断很准确,但是如果是对于自定义的函数就不能判断的很清楚。
因为想要自定义函数判断出是继承自那个函数的话,一般都是与原型链相关的,即instanceof,constructor
如若有误,请务必立即指正

浙公网安备 33010602011771号