1.typeof

  1. console.log(typeof "");//string
  2. console.log(typeof 1); //number
  3. console.log(typeof true);//boolean
  4. console.log(typeof undefined);//undefined
  5. console.log(typeof function () { });//function
  6. console.log(typeof null);//object
  7. console.log(typeof []);//object
  8. console.log(typeof {});//object

image.png
可以发现typeof只能区分基本数据类型,不能区分null、数组和对象。

1.1为什么 执行typeof null时会返回字符串“object”?

原理是这样的。不同的对象在底层都表示为二进制,所有对象类型二进制前三位都是0,在javascript中二进制前三位都为0的话会被判断为object类型,null的二进制表示全0(000000),自然前三位也是0,所以执行typeof时会返回“object”

1.2为什么function也是一种特殊的对象,typeof 返回的却是“function”?

因为function作为一种特殊的可执行对象,底层二进制表示的前三位不是3个0,所以返回function;
所以,typeof Object Array,String,Boolean,Date,RegExp这些构造函数都是返回function。

2.instanof

  1. console.log("1" instanceof String);//false
  2. console.log(1 instanceof Number);//false
  3. console.log(true instanceof Boolean);//false
  4. //console.log(null instanceof Null);
  5. //console.log(undefined instanceof Undefined);
  6. console.log([] instanceof Array);//true
  7. console.log(function () { } instanceof Function);//true
  8. console.log({} instanceof Object);//true

image.png
可以看到前三个都是以对象字面量创建的基本数据类型,但是却不是所属类的实例,这个就有点怪了。后面三个是引用数据类型,可以得到正确的结果。如果我们通过new关键字去创建基本数据类型,你会发现,这时就会输出true,如下:

JS数据类型检测有哪些办法 - 图3
接下再来说说为什么null和undefined为什么比较特殊,实际上按理来说,null的所属类就是Null,undefined就是Undefined,但事实并非如此:控制台输出如下结果:
image.png
image.png
l浏览器压根不认识这两货,直接报错。在第一个例子你可能已经发现了,typeof null的结果是object,typeof undefined的结果是undefined
尤其是null,其实这是js设计的一个败笔,早期准备更改null的类型为null,由于当时已经有大量网站使用了null,如果更改,将导致很多网站的逻辑出现漏洞问题,就没有更改过来,于是一直遗留到现在。作为学习者,我们只需要记住就好。

3.constructor

  1. console.log(("1").constructor === String);
  2. console.log((1).constructor === Number);
  3. console.log((true).constructor === Boolean);
  4. //Uncaught TypeError: Cannot read property 'constructor' of null
  5. // console.log((null).constructor === Null);
  6. // Uncaught TypeError: Cannot read property 'constructor' of undefined
  7. // console.log((undefined).constructor === Undefined);
  8. console.log(([]).constructor === Array);
  9. console.log((function () { }).constructor === Function);
  10. console.log(({}).constructor === Object);

image.png
(这里依然抛开null和undefined)乍一看,constructor似乎完全可以应对基本数据类型和引用数据类型,都能检测出数据类型,事实上并不是如此,来看看为什么:

  1. function Fn() { };
  2. Fn.prototype = new Array();
  3. var f = new Fn();
  4. console.log(f.constructor === Fn);//false
  5. console.log(f.constructor === Array);//true

我声明了一个构造函数,并且把他的原型指向了Array的原型,所以这种情况下,constructor也显得力不从心了。
看到这里,是不是觉得绝望了。没关系,终极解决办法就是第四种办法,看过jQuery源码的人都知道,jQuery实际上就是采用这个方法进行数据类型检测的。

4.Object.prototype.toString.call()

  1. var a = Object.prototype.toString;
  2. console.log(a.call("aaa"));
  3. console.log(a.call(1));
  4. console.log(a.call(true));
  5. console.log(a.call(null));
  6. console.log(a.call(undefined));
  7. console.log(a.call([]));
  8. console.log(a.call(function () { }));
  9. console.log(a.call({}));

image.png
可以看到,所有的数据类型,这个办法都可以判断出来。那就有人质疑了,假如我把他的原型改动一下呢?如你所愿,我们看一下:

JS数据类型检测有哪些办法 - 图8
可以看到,依然可以得到正确的结果。

使用的过程中,可以这样封装函数:

  1. function isType(type) {
  2. return function(obj) {
  3. return {}.toString.call(obj) == "[object " + type + "]"
  4. }
  5. }
  6. var isObject = isType("Object")
  7. var isString = isType("String")
  8. var isArray = Array.isArray || isType("Array")
  9. var isFunction = isType("Function")
  10. var isUndefined = isType("Undefined")
  11. console.log(isString("1")//true