Javascript 中的变量类型判断

熟悉 JavaScript 数据类型的话我们知道在 JavaScript 这门语言中存在基本类型(值类型),如Undefined ,Null,Boolean,Number,String,可以类比数据结构中只有栈内存而没有堆内存;还有一种就是引用类型,如Function,Array,Object, Date, RegExp,同理在数据结构中既有栈内存也有堆内存,栈内存中是存放的一个堆内存的引用,也可以理解为指针。这里暂时不讨论包装类型,因为它也算是引用类型的一种。还有一个要注意的地方,String 类型在 Java 中是属于引用类型,但是 JavaScript 里面看做了基本类型。

这里我们要判断一个变量是不是基本类型或者引用类型该怎么做呢?聪明的你肯定能立马想到:简单类型的类型判断用 typeof,引用类型的类型判断用 instanceof。我们看一下代码,

console.log(typeof x);      // undefined
console.log(typeof 10);     // number
console.log(typeof 'abc');  // string
console.log(typeof true);   // boolean
console.log(typeof null);   // object  这是错误的


console.log(Function instanceof Object);      // true
console.log(Object instanceof Function);      // true
console.log(Function instanceof Function);    // true

我们发现基本类型时候其他都正常但是 Null 是指向了 object,这是为啥呢?还有下面的 instanceof 三个都是 true,好奇怪啊,但是自己去运行一下还真的是正确的?这又是为啥呢?带着疑问我们继续往下走。

首先看一下为啥 typeof null 报的是 object,参考 ECMA 中规定,里面规定了 typeof(null) 的值是"object",但是为什么在有 Null type 的情况下不返回 "null" 呢?我上知乎找了下仅供参考:


Javascript 中的变量类型判断_第1张图片
image.png

基于这个原因所以我们只用 typeof 判断除了 null 的基本类型

我们接着来看一下 instanceof 如何判断的 ,

a instanceof A

沿着 a 的 __proto__ 这条线来找,同时沿着 b 的 prototype 这条线来找,
如果两条线能找到同一个引用,即同一个对象,那么就返回 true 。
如果找到终点还未重合,则返回 false 。

通过JavaScript的原型链可以找到同一个对象,所以上面的三条记录都是true,并且因为 instanceof 沿着原型链查找,所以无法判断基本类型,根据这个规则以及下面的图示我们来快速理解一下


Javascript 中的变量类型判断_第2张图片
image.png

其实除了上面的 typeof 以及 instanceof 之外,我们还可以通过另外两种更强大的类型检测方法,那就是 Object.prototype.toString.call 以及 Constructor,如果有阅读过源码的话我们就能发现,源码中检测类型一般用到的是 Object.prototype.toString.call,我们来看一下代码中这两种是如何判断的

let test = function() {}
console.log(Object.prototype.toString.call(test))    // [object Function]

let test = [1, 2, 3]
console.log(Object.prototype.toString.call(test))    // [object Array]

let test = Null
console.log(Object.prototype.toString.call(test))    // [object Null]

let test = undefined
console.log(Object.prototype.toString.call(test))    // [object Undefined]

let test = '123e'
console.log(Object.prototype.toString.call(test))    // [object String]

...       // 经过测试我们发现他能满足基本类型和引用类型,很强大~

constructor 属性: JavaScript 中,每个对象都有一个 constructor 属性,它引用了初始化该对象的构造函数,常用于判断未知对象的类型。这也是一个很强大的方法,不过不适用于 null 和 undefined, 我们还是看控制台输出,

let aa = null 
aa.constructor()      // undefined 和 null 报错

let test = '123e'
test.constructor()    // ""

let arr = [1,2,3,4]
arr.constructor()      // []

let func = function(){}
func.constructor()     // ƒ anonymous() {}

let aa = new RegExp
aa.constructor()       //  /(?:)/

....   // 由于 对象 存在构造函数这个属性,所以我们也可以很方便去通过这个来判断类型

总结一下:

我们判断基本类型可以通过 typeof 简单判断,当然是用 Object.prototype.toString.call 更加精准,日常开发中也推荐使用~ 内置对象就是我们经常用到的Array、 Math、 RegExp 以及 Date 等等,这种类型我们不能用 typeof 只能使用其他三种方式去判断;自定义对象就是我们自己通过 new 或者 Object.create() 等等创建出来的对象(这个也可以单独拿出来讲,不过还是下次对比不同创建对象方式以及继承的差异性里面讲),这种自定义的对象我们可以使用 instanceof 以及 Constructor 构造函数去做类型检测,下面是一个图示对比

Javascript 中的变量类型判断_第3张图片
image.png

你可能感兴趣的:(Javascript 中的变量类型判断)