判断 JS 数据类型的方法

发布于 2023-01-05 12:50:27 字数 7682 浏览 118 评论 0

判断非 Object 类型用 typeof,判断 Object 可以用 constructor(但要注意继承问题,如有继承问题可以用 constructor,文中有说明)和 instanceof。判断对象中的 Array 类型可以用 instanseof(用它来判断 Object 会有误差),通用判断方式用 Object.prototype.toString 和 jquery.type()

在 ECMAScript 规范中,共定义了 7 种数据类型,分为 基本类型 和 引用类型 两大类,如下所示:

  • 基本类型:String、Number、Boolean、Symbol、Undefined、Null
  • 引用类型:Object

基本类型也称为简单类型,由于其占据空间固定,是简单的数据段,为了便于提升变量查询速度,将其存储在栈中,即按值访问。

引用类型也称为复杂类型,由于其值的大小会改变,所以不能将其存放在栈中,否则会降低变量查询速度,因此,其值存储在堆(heap)中,而存储在变量处的值,是一个指针,指向存储对象的内存处,即按址访问。引用类型除 Object 外,还包括 Function 、Array、RegExp、Date 等等。

鉴于 ECMAScript 是松散类型的,因此需要有一种手段来检测给定变量的数据类型。对于这个问题,JavaScript 也提供了多种方法,但遗憾的是,不同的方法得到的结果参差不齐。

下面介绍常用的5种方法,并对各个方法存在的问题进行简单的分析。

1、最常见的判断方法:typeof

typeof 用的比较多的时候,是判断某个全局变量在不在,假如某个页面定义了一个全局变量。假如你做如下判断:

// haorooms 是全局变量
if(haorooms!=undefined){
}
// js 会报错:Uncaught ReferenceError: haorooms is not defined

解决的方法是我们如下写:

if(typeof haorooms!=undefined){
}

用了 typeof 之后,就不会报错了!这是 typeof 的应用之一!

typeof 是一个操作符,其右侧跟一个一元表达式,并返回这个表达式的数据类型。返回的结果用该类型的字符串(全小写字母)形式表示,包括以下 7 种:number、boolean、symbol、string、object、undefined、function 等。

typeof ''; // string 有效
typeof 1; // number 有效
typeof Symbol(); // symbol 有效
typeof true; //boolean 有效
typeof undefined; //undefined 有效
typeof null; //object 无效
typeof [] ; //object 无效
typeof new Function(); // function 有效
typeof new Date(); //object 无效
typeof new RegExp(); //object 无效

有些时候,typeof 操作符会返回一些令人迷惑但技术上却正确的值:

  • 对于基本类型,除 null 以外,均可以返回正确的结果。
  • 对于引用类型,除 function 以外,一律返回 object 类型。
  • 对于 null ,返回 object 类型。
  • 对于 function 返回 function 类型。

其中,null 有属于自己的数据类型 Null , 引用类型中的 数组、日期、正则 也都有属于自己的具体类型,而 typeof 对于这些类型的处理,只返回了处于其原型链最顶端的 Object 类型,没有错,但不是我们想要的结果。

对于 null->"object" 的问题,仅仅 typeof 无解,记住有这么个坑即可。

而关于 array->"object" 的问题,建议使用:Array.isArray([]) // true 来判断即可。

2、判断已知对象类型的方法: instanceof

可以用其判断是否是数组。

var haorooms=[];
console.log(haorooms instanceof Array) // 返回 true

instanceof 是用来判断 A 是否为 B 的实例,表达式为:A instanceof B,如果 A 是 B 的实例,则返回 true,否则返回 false。 在这里需要特别注意的是:instanceof 检测的是原型,我们用一段伪代码来模拟其内部执行过程:

instanceof (A,B) = {
    var L = A.__proto__;
    var R = B.prototype;
    if(L === R) {
        // A的内部属性 __proto__ 指向 B 的原型对象
        return true;
    }
    return false;
}

从上述过程可以看出,当 A 的 proto 指向 B 的 prototype 时,就认为 A 就是 B 的实例,我们再来看几个例子:

[] instanceof Array; // true
{} instanceof Object;// true
new Date() instanceof Date;// true

function Person(){};
new Person() instanceof Person;

[] instanceof Object; // true
new Date() instanceof Object;// true
new Person instanceof Object;// true

我们发现,虽然 instanceof 能够判断出 [] 是 Array 的实例,但它认为 [] 也是 Object 的实例,为什么呢?

我们来分析一下 []、Array、Object 三者之间的关系:

从 instanceof 能够判断出 [].proto 指向 Array.prototype,而 Array.prototype.proto 又指向了 Object.prototype,最终 Object.prototype.proto 指向了 null,标志着原型链的结束。因此,[]、Array、Object 就在内部形成了一条原型链。

从原型链可以看出,[] 的 proto 直接指向 Array.prototype,间接指向 Object.prototype,所以按照 instanceof 的判断规则,[] 就是 Object 的实例。依次类推,类似的 new Date()、new Person() 也会形成一条对应的原型链 。因此 instanceof 只能用来判断两个对象是否属于实例关系, 而不能判断一个对象实例具体属于哪种类型。

instanceof 操作符的问题在于,它假定只有一个全局执行环境。如果网页中包含多个框架,那实际上就存在两个以上不同的全局执行环境,从而存在两个以上不同版本的构造函数。如果你从一个框架向另一个框架传入一个数组,那么传入的数组与在第二个框架中原生创建的数组分别具有各自不同的构造函数。

var iframe = document.createElement('iframe');
document.body.appendChild(iframe);
xArray = window.frames[0].Array;
var arr = new xArray(1,2,3); // [1,2,3]
arr instanceof Array; // false

针对数组的这个问题,ES5 提供了 Array.isArray() 方法 。该方法用以确认某个对象本身是否为 Array 类型,而不区分该对象在哪个环境中创建。

if (Array.isArray(value)){
   //对数组执行某些操作
}

Array.isArray() 本质上检测的是对象的 [[Class]] 值,[[Class]] 是对象的一个内部属性,里面包含了对象的类型信息,其格式为 [object Xxx] ,Xxx 就是对应的具体类型 。对于数组而言,[[Class]] 的值就是 [object Array] 。

alert(c instanceof Array) -----------> true
alert(d instanceof Date)
alert(f instanceof Function) --------> true
alert(f instanceof function) --------> false

注意:instanceof 后面一定要是对象类型,并且大小写不能错,该方法适合一些条件选择或分支。 

3、根据对象的 constructor 判断: constructor

alert(c.constructor === Array) ----> true
alert(d.constructor === Date) -----> true
alert(e.constructor === Function) ----> true

注意: constructor 在类继承时会出错

function A(){};
function B(){};
A.prototype = new B(); //A继承自B
var aObj = new A();
alert(aobj.constructor === B) -------> true;
alert(aobj.constructor === A) -------> false;

而 instanceof 方法不会出现该问题,对象直接继承和间接继承的都会报 true:

alert(aobj instanceof B) --------> true;
alert(aobj instanceof A) --------> true;

言归正传,解决 construtor 的问题通常是让对象的 constructor 手动指向自己:

aobj.constructor = A; // 将自己的类赋值给对象的 constructor 属性
alert(aobj.constructor === A) -------> true;
alert(aobj.constructor === B) -------> false; // 基类不会报 true 了;

4、繁琐且通用:toString

toString() 是 Object 的原型方法,调用该方法,默认返回当前对象的 [[Class]] 。这是一个内部属性,其格式为 [object Xxx] ,其中 Xxx 就是对象的类型。

对于 Object 对象,直接调用 toString() 就能返回 [object Object] 。而对于其他对象,则需要通过 call / apply 来调用才能返回正确的类型信息。

Object.prototype.toString.call('') ;   // [object String]
Object.prototype.toString.call(1) ;    // [object Number]
Object.prototype.toString.call(true) ; // [object Boolean]
Object.prototype.toString.call(Symbol()); //[object Symbol]
Object.prototype.toString.call(undefined) ; // [object Undefined]
Object.prototype.toString.call(null) ; // [object Null]
Object.prototype.toString.call(new Function()) ; // [object Function]
Object.prototype.toString.call(new Date()) ; // [object Date]
Object.prototype.toString.call([]) ; // [object Array]
Object.prototype.toString.call(new RegExp()) ; // [object RegExp]
Object.prototype.toString.call(new Error()) ; // [object Error]
Object.prototype.toString.call(document) ; // [object HTMLDocument]
Object.prototype.toString.call(window) ; //[object global] window 是全局对象 global 的引用

5、无敌万能的方法 jquery.type()

如果对象是 undefined 或 null,则返回相应的 undefined 或 null。

jQuery.type( undefined ) === "undefined"
jQuery.type() === "undefined"
jQuery.type( window.notDefined ) === "undefined"
jQuery.type( null ) === "null"

如果对象有一个内部的 [[Class]] 和一个浏览器的内置对象的 [[Class]] 相同,我们返回相应的 [[Class]] 名字。 (有关此技术的更多细节。 )

jQuery.type( true ) === "boolean"
jQuery.type( 3 ) === "number"
jQuery.type( "test" ) === "string"
jQuery.type( function(){} ) === "function"
jQuery.type( [] ) === "array"
jQuery.type( new Date() ) === "date"
jQuery.type( new Error() ) === "error" // as of jQuery 1.9
jQuery.type( /test/ ) === "regexp"

其他一切都将返回它的类型 object。

总结:通常情况下用 typeof 判断就可以了,遇到预知 Object 类型的情况可以选用 instanceof 或 constructor 方法,实在没辙就使用 $.type() 方法。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

戈亓

暂无简介

文章
评论
27 人气
更多

推荐作者

櫻之舞

文章 0 评论 0

弥枳

文章 0 评论 0

m2429

文章 0 评论 0

野却迷人

文章 0 评论 0

我怀念的。

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文