隐式类型转换以及类型判断的方式(有坑)

== 的隐式类型转换

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

 

如若有误,请务必立即指正

posted @ 2020-08-14 15:51  kkkllo  阅读(898)  评论(0)    收藏  举报