前言
在处理数据时,数据类型的判断是经常用到的逻辑,但是判断方法有很多,选哪个方法呐?要就要看自己的业务场景了,下边来简单说下各种方法和他们的不同之处。
我这里在列举这几种判断方法的同时,主要是按照自己的理解来解释下原理,为什么他们的判断结果是这样子,所以有点啰嗦~见谅😀
发现我的理解有偏差的地方,请大家帮忙指出~谢谢~😚
1、typeof方法
说到类型判断第一个进入脑海的方法大概就是typeof了
-
调用格式
typeof 123 //'number'
typeof '123' //'string'
typeof (6==7) //'boolean'
typeof undefined //'undefined'
typeof Symbol('1') //'symbol'
typeof [] //'object'
typeof {} //'object'
typeof null //'object'
-
判断特点:
通过前边的调用结果我们也发现,typeof只能判断简单数据类型以及symbol和undefined的具体数据类型;
Array、Object和null的判断结果都是'object'。
这是为什么呐?
-
判断分析:
js 在底层存储变量的时候,会在变量的机器码的低位1-3位存储其类型信息:
- 000:对象(包括所有的可以被实例化对象,Array类型的数据也在其中)
- 010:浮点数
- 100:字符串
- 110:布尔
- 1:整数
undefined和null有点特殊:
undefined:用 −2^30 整数来表示;
null:所有机器码均为0
typeof就是根据低位的1-3位来判断类型的,能够准确区分出number、string和boolean类型。
对象类型低位全是000,没法去区分是什么对象类型,而且还有一个大的误区,null的所有机器码都是0,当然也包括低3位,所以也被认为是object类型。
这样也就解释了我们上边每个类型的判断结果了。
-
使用注意
本着存在即合理的理念,我们也不能说typeof判断方法是不好的,当我们了解了他的判断结果后,可以选择性的去使用。
一般用来判断当前变量是不是赋值或有没有创建。
2、instanceof方法
从字面上来看,这方法是通过判断目标数据是不是对应的构造函数的实例,来判断数据类型
-
调用格式
'' instanceof String // false
123 instanceof Number // false
true instanceof Boolean // false
Symbol(1) instanceof Symbol // false
[] instanceof Array //true
({}) instanceof Object //true
undefined和null在判断的时候会报错,因为null和undefined都没有对应的构造函数。
-
判断分析
其实这方法是判断当前数据是不是对应构造函数的实例,如果是的话,就属于构造函数对应的类型。
so:
1. 字面量创建的字符串、布尔值、数字
是简单数据类型,不属于不是构造函数new的实例对象。所以无法通过instanceof判断类型;
2、Symbol不是一个构造函数,没办法去new一个实例,所以它也无法通过instanceof判断;
3、而数组和对象
是符合条件的,他们是对象类型,同时也可以通过Array和Object去new出来一个实例对象。可以通过这个方法判断数据类型。
4、undefined和null作为特殊数据类型,他们的所属类是Null
和 Undefined
,但是浏览器把这两个类保护起来了,不允许我们在外面访问使用。去用这个方法判断的时候,会直接报错。大家可以试一下,我这里就不写报错过程了
-
使用注意
这个方法可以用来区分对象类型的具体类型,但是没法判断其他类型的数据,使用场景比较小。
3、constructor方法
constructor字面上的意思就是通过判断当前数据的构造函数来判断数据类型
-
调用
'123'.constructor == String //true
(123).constructor == Number //true
true.constructor == Boolean //true
[].constructor == Array //true
({}).constructor == Object //true
Symbol(1).constructor === Symbol //true
-
判断分析
通过上边的调用很明显就是判断当前数据的constructor
属性的指向。如果当前数据的构造函数和制定的构造函数相等,就判断其为对应的类型。
我画了一个简单的原型链示意图:
上图中Person是构造函数,person1是它的实例对象,实例对象本身是没有
constructor
属性的,但是根据原型链的继承原理,我们会继续到它的__proto__
(原型)上去找,在原型上有个 constructor
属性,指向了构造函数Person。
而我们这个方法基本上也是这个原理:
1、作为简单数据类型的'123'、123和true
,它们本身不是构造函数的实例,但是他们身上有__proto__
属性分别指向了String、Number、Boolaen
的原型对象。而这个原型下边的constructor
属性指向了对应的构造函数。
2、Symbol本身不是构造函数,但是通过Symbol(1)创建的Symbol类型的值却有一个'constructor'属性指向了Symbol函数,所以他也可以通过这个方法判断数据类型。
3、 关于undefined和null这两个大冤种,大家看下边的截图就明白了:
-
使用注意
通过上边的介绍我们发现了,constructor方法是除了undefined和null之外,其他常见数据类型都能判断,到现在我们发现这些方法都有自己的缺陷,不仅感叹:“世间安有双全法,不负如来不负卿”。
但是接下来这个方法就是我们期盼已久的全能型选手了~
4、Object.prototype.toString.call()
直接上调用方法示例:
Object.prototype.toString.call('123')
==>'[object String]'
Object.prototype.toString.call(123)
==>'[object Number]'
Object.prototype.toString.call([123])
==>'[object Array]'
Object.prototype.toString.call(true)
==>'[object Boolean]'
Object.prototype.toString.call({a:123})
==>'[object Object]'
Object.prototype.toString.call(Symbol(1))
==>'[object Symbol]'
Object.prototype.toString.call(null)
==>'[object Null]'
Object.prototype.toString.call(undefined)
==>'[object Undefined]'
-
判断分析
通过以上的示例大家也发现了这个方法可以判断所有类型,其实是因为js中有句话:万物皆对象,Object中有toString方法,所有对象最后原型链的尽头都是Object的原型。
通过call()来改变了方法的this指向,this指向了我们需要判断的数据,也就返回了各自对应的type。