史上最全js判断数据类型方法总结(typeof、instanceof、constructor、Object.prototype.toString.call()的应用场景)

目录

一、数据类型概述

二、数据类型的判断方法

1. typeof方法

2. instanceof方法

3. constructor方法

4. Object.prototype.toString.call()方法


判断数据类型是我们工作和面试中经常会遇到的问题,因此本文对该问题进行了些许的整理,供大家参考。

一、数据类型概述

二、数据类型的判断方法

目前常用的判断数据类型的方法有四种,分别为:typeof、instanceof、constructor以及Object.prototype.toString.call(),其中判断最为准确的方法是最后一种Object.prototype.toString.call(),接下来将详细讲解每种不同方法的优缺点。

1. typeof方法

typeof 运算符后可直接跟变量名或者跟字面值。typeof 可以准确判断数字 Number,布尔值 Boolean,字符串 String,函数 Function,Undefined 以及对象 Object,但是不能正确判断 null 和 array 类型(这两个判断的结果为对象 Object)。

var a = 2;
document.write("chaopy----------------typeof a = "+typeof a+"<br>");            // number
document.write("chaopy----------------typeof 2 = "+typeof 2+"<br>");           // number
document.write("chaopy-------------typeof true = "+typeof true+"<br>");       // boolean
document.write("chaopy--------------typeof 'str' = "+typeof 'str'+"<br>");   // string
document.write("chaopy----------typeof [] = "+typeof []+"<br>");//object []数组的数据类型在typeof中被解释为object
document.write("chaopy-----typeof function(){} = "+typeof function(){}+"<br>"); // function
document.write("chaopy----------------typeof {} = "+typeof {}+"<br>");         // object
document.write("chaopy------typeof undefined = "+typeof undefined+"<br>");    // undefined
document.write("chaopy-----------typeof null = "+typeof null+"<br>");//object null的数据类型被typeof解释为object

结果如下:

优点:只在区别对象和原始类型的时候才有用(由于null表示对空对象的引用,故也可认为null是引用类型,即对象类型)。

缺点:不能用于区分一种对象类型和另一种对象类型

2. instanceof方法

instanceof 运算符要求其左边的运算数是一个对象,右边的运算数是对象类的名字或构造函数。如果 object 是 class 或构造函数的实例,则 instanceof 运算符返回 true。如果 object 不是指定类或函数的实例,或者 object 为 null,则返回 false。

document.write("chaopy-------------( 'str' instanceof String ) = " + ( 'str' instanceof String )+"<br>");//false
document.write("chaopy-------------( 2 instanceof Number ) = " + ( 2 instanceof Number )+"<br>");       //false
document.write("chaopy----------( true instanceof Boolean ) = " + ( true instanceof Boolean )+"<br>");//false 
document.write("chaopy---(function(){} instanceof Function)= "+(function(){} instanceof Function )+"<br>");//true
document.write("chaopy-----------------( [] instanceof Array ) = " + ( [] instanceof Array )+"<br>");    //true
document.write("chaopy----------------( {} instanceof Object ) = " + ( {} instanceof Object )+"<br>"); //true

结果如下:

分析:

以上结果显示,直接的字面量值判断数据类型,只有引用数据类型(Array,Function,Object)被精准判断,其他(数值Number,布尔值Boolean,字符串String)字面值不能被instanceof精准判断。

我们来看一下 instanceof 在MDN中的解释:instanceof 运算符用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性。即判断对象是否是某一数据类型(如Array)的实例,请重点关注一下是判断一个对象是否是数据类型的实例。在这里字面量值2, true ,'str'不是实例,所以判断值为false。当字面值被实例化了,他们的判断结果则会变为 true,如下所示:

接着来看一下 undefined 和 null ,按理来说,null的所属类就是Null,undefined就是Undefined,但事实并非如此,控制台输出如下结果:

浏览器认为Null,Undefined不是构造器。但是在 typeof 中你可能已经发现了,typeof null的结果是Object,typeof undefined的结果是Undefined ,这是怎么回事呢?

尤其是null,其实这是js发展过程中设计者的重大失误,早期准备更改null的类型为Null,由于当时已经有大量网站使用了Null,如果更改,将导致很多网站的逻辑出现漏洞问题,就没有更改过来,于是一直遗留到现在。作为学习者,我们只需要记住就好。

3. constructor方法

JavaScript中,每个对象都有一个constructor属性,它引用了初始化该对象的构造函数,常用于判断未知对象的类型。如给定一个求知的值通过typeof运算符来判断它是原始的值还是对象。如果是对象,就可以使用constructor属性来判断其类型。

document.write("chaopy---(function(){}).constructor===Function="+((function(){}).constructor===Function)+"<br>");
document.write("chaopy----------(('str').constructor === String) = " + (('str').constructor === String)+"<br>");
document.write("chaopy---------((true).constructor === Boolean) = " + ((true).constructor === Boolean)+"<br>");  
document.write("chaopy--------------(({}).constructor === Object) = " + (({}).constructor === Object)+"<br>");
document.write("chaopy---------------(([]).constructor === Array) = " + (([]).constructor === Array)+"<br>");
document.write("chaopy------------((2).constructor === Number) = " + ((2).constructor === Number)+"<br>");

结果如下:


用costructor来判断类型看起来是完美的,然而,如果我创建一个对象,更改它的原型,这种方式也变得不可靠了。

null、undefined没有construstor方法,因此constructor不能判断undefined和null,并且它是不安全的,因为contructor的指向是可以被改变。

4. Object.prototype.toString.call()方法

首先,我们来了解一下toString()方法:

案例一

var pro = Object.prototype;
var pr = pro.__proto__;        //ie11之前版本不支持该属性
console.log(typeof pro);      //"object"
console.log(String(pro));    //"[object Object]"
console.log(pro.hasOwnProperty("toString"));  //true
console.log(typeof pr);                      //"object"
console.log(String(pr));                    //"null"
console.log(pr.hasOwnProperty("toString"));//报错

结果如下:

分析:

由以上可知,toString()是定义在Object.prototype上;所以所有对象均可用toString()方法。(但为什么当对象是object的时候,输出的是'[object object]',而其他类型输出的却是类似本身的值?【个人理解:因为其他类型的对象引用的是重写后的toString()方法】)

toString() 是 Object 的原型方法,调用该方法,默认返回当前对象的[[Class]] 。这是一个内部属性,其格式为 [object Xxx] ,其中 Xxx 就是对象的类型。对于 Object 对象,直接调用 toString()  就能返回 [object Object] 。而对于其他对象,则需要通过 call / apply 来调用才能返回正确的类型信息。

根据ECMA-262规范可知:当Object.prototype.toString(o)执行后,会执行以下步骤:

(1)获取对象o的class属性;

(2)连接字符串:"[object "+结果(1)+"]" ;

(3)返回 结果(2) 。

上面的规范步骤定义了 Object.prototype.toString 的行为:首先,取得对象的一个内部属性[[Class]],然后依据这个属性,返回一个类似于 "[object Array]" 的字符串作为结果([[]]用来表示语言内部用到的、外部不可直接访问的属性,称为 "内部属性")。利用这个方法,再配合 call,我们可以取得任何对象的内部属性 [[Class]](因为Object.prototype是所有对象的原型,故任何对象均可调用原型上的方法),然后把类型检测转化为字符串比较,以达到我们的目的。

案例二

var a = Object.prototype.toString;
console.log(a.call({}));       //[object Object]
console.log(a.call(2));       //[object Number]
console.log(a.call(true));   //[object Boolean]
console.log(a.call('str')); //[object String]
console.log(a.call([]));   //[object Array]
console.log(a.call(function(){}));  //[object Function]
console.log(a.call(undefined));    //[object Undefined]
console.log(a.call(null));        //[object Null]

结果如下:

分析:

使用 Object 对象的原型方法 toString ,使用 call 进行狸猫换太子,借用Object的 toString  方法,结果精准的显示我们需要的数据类型。即使我们改变对象的原型,他依然会显示正确的数据类型。

案例三

function Fn(){};
Fn.prototype=new Array();
console.log(Object.prototype.toString(Fn));      //[object Object]   (1)
console.log(Object.prototype.toString.call(Fn));//[object Function]  (2)

结果如下:

分析:

注释(1)处没有使用call()方法,打印结果为[object Object],原因是其直接调用的是function重写之后的toString()方法;

注释(2)处使用了call()方法,打印结果为[object Function],原因是其借用了Object对象的原型方法toString()。

由此可知:即使我们改变Fn对象的原型,使用Object.prototype.toString.call(Fn)方法依然能够正确判断Fn的数据类型。

参考文献:

  1. js检测数据类型四种办法》原文链接:https://www.cnblogs.com/zt123123/p/7623409.html

  2. 浅谈JS中String()与.toString()的区别》原文链接:https://blog.csdn.net/huang100qi/article/details/80543045

发布了33 篇原创文章 · 获赞 35 · 访问量 813

猜你喜欢

转载自blog.csdn.net/chaopingyao/article/details/104626369
今日推荐