如何判断JavaScript变量的类型

作者:明达 来源:七月佑安 时间:2009-02-25 12:28:00 

数据类型是所有开发语言的基础,JavaScript虽然是一个弱类型的脚本语言,但是在数据类型上也有很多讲究的,看了淘宝UED玉伯的一篇文章,末尾有一个判断数据类型的函数,仔细揣摩后发现有一些改进的余地,于是有了本文。目标就是一个可以提供足够类型参考信息的函数。

【测试地址1】http://lab.cuimingda.com/jquery/tof/

【测试地址2】http://lab.cuimingda.com/detection/window.html

在JavaScript中,变量中可以存储的值主要有两种类型:原始值(primitive value)和引用值(reference value)。前者通常是固定而又简单的数据,存储在栈(stack)中,而后者则是比较大的对象,存储在堆(heap)中,而对于后者的调用,是通过存储在栈中的指针来完成的。原始类型有五种:Number、String、Boolean、Null和Undefined,引用类型都继承自Object。

我们的最终目标就是一个叫做tof的全局函数,返回值为字符串,代表anything对应的类型,因为所有的引用类型都是object,所以这里返回的类型应该不局限于数据类型,应该尽可能的反映出anything的真实信息:

/*
var t = tof(anything);
*/

第一个实现肯定是利用传统的typeof来实现:

/*
function tof(val) {
return typeof(val);
}
*/

typeof可以得出的结论有五种:undefined、string、number、boolean和object。和原始类型比较还差个null,这个比较特殊,typeof(null)的返回值是object,这本来是JavaScript早期的bug,但后来却被写入了ECMAScript标准,可以理解为null是object的占位符。很明显,typeof无法满足我们的需求。

幸好Google的Mark Miller找到另外一个非常有效的判断数据类型的方法,就是利用Object.prototype.toString.call,用这个方法对Date类型数据进行计算,得到的结果是“[object Date]”,对于其他类型,前半部分始终是object,后半部分会发生变化,这样就很方便我们判断了。jQuery从1.3开始,也采用了这种方法判断array和function。下面我们来改进一下:

/*
function tof(val) {
return Object.prototype.toString.call(val).match(/object\s(\w+)/)[1];
}
*/

这个函数现在已经可以判断非常多的情况了,等等,undefined和null怎么返回的是Window(Firefox 3.0.6和Opera 9.63),在IE 7下返回Object,在Chrome返回builtins,在Safari 3.2下返回DOMWindow,明显优于这两个被定义为全局对象的属性,在不同的浏览器下挂到了不同的全局对象上。既然这么特殊,只能对他们单独有待一下了:

/*
function tof(val) {
var t;
switch(val) {
 case null: t = "null"; break;
 case undefined: t = "undefined"; break;
 default:
     t = Object.prototype.toString.call(val).match(/object\s(\w+)/)[1];
     break;
}
return  t.toLowerCase();
}
*/

到这里,我们已经可以判断很多object了,包括array、regexp、date等。让我们再多想一些,比如你碰到过需要判断DOM元素类型的情况么?这个首先要说明个问题,我们访问DOM,其实有两种方式,一种是通过树型的继承方式,就是Element为基础的,另外一种是构建在xml基础上的node模式,而对应每个节点都有tagName和nodeName两个属性,大部分时候要求是必须一样的,一些特殊节点只有nodeName,没有tagName,比如document的nodeName为“#document”,tagName为空值。

/*
function tof(val) {
var t;
switch(val) {
 case null: t = "null"; break;
 case undefined: t = "undefined"; break;
 default:
     t = val.nodeName || Object.prototype.toString.call(val).match(/object\s(\w+)/)[1];
     break;
}
return  t.toLowerCase();
}
*/

如果是DOM元素,首先取节点名称,取不到再用老办法判断对象类型。这样,不管是通过document.createElement构建的元素,还是通过document.getElementById获取的元素,都可以得到一个可以参考的类型了,注意此类型非彼类型,只是元素名称而已。经过了以上几个步骤,还有什么情况会出现object呢,其中一个就是我们自己定义的对象,或者称为类?这里我们采用构造函数来搞定。

/*
function tof(val) {
var t;
switch(val) {
 case null: t = "null"; break;
 case undefined: t = "undefined"; break;
 default:
     t = val.nodeName || Object.prototype.toString.call(val).match(/object\s(\w+)/)[1];
     if(!!val.constructor && t.toLowerCase() === "object") {
         t = val.constructor.toString().match(/^\s*function\s(\w+)/)[1];
     }
     break;
}
return  t.toLowerCase();
}
*/

构造函数的判断放到最后,不得已而为之的情况。一是要处理那些还处于object状态的,二是要确保人家要有构造函数,可不是每个对象都有构造函数的。构造函数的类型是function,如果直接拿来比较在有些时候会有问题,比如不同框架的时候。所以我们将function的内容转换为字符串,通过正则表达式来取函数名。这里有个插曲就是,IE很缺德,在function前面加了一个空格,害我多调了好半天正则表达式。

标签:JavaScript,变量,类型,脚本
0
投稿

猜你喜欢

  • MySQL操作数据库和表的常用命令新手教程

    2024-01-23 23:18:36
  • python导出chrome书签到markdown文件的实例代码

    2022-08-26 00:49:36
  • 一篇文章介绍redux、react-redux、redux-saga总结

    2023-08-22 16:56:32
  • Windows10下mysql 8.0.19 安装配置方法图文教程

    2024-01-21 06:33:27
  • 可插入图片的TEXT文本框

    2024-02-25 20:07:36
  • python热力图实现的完整实例

    2023-03-02 17:10:35
  • python中的多重继承实例讲解

    2022-06-18 01:51:05
  • 微信小程序实现登录注册tab切换效果

    2024-04-29 13:11:29
  • Python开发桌面小程序功能

    2023-07-01 14:46:59
  • 关于python中remove的一些坑小结

    2022-09-22 02:14:31
  • python pygame实现五子棋双人联机

    2022-04-12 22:41:04
  • 19个ASP编程基础典型代码

    2008-10-23 15:46:00
  • python使用opencv resize图像不进行插值的操作

    2023-09-12 15:04:25
  • python中ImageTk.PhotoImage()不显示图片却不报错问题解决

    2023-08-26 18:12:06
  • influx+grafana自定义python采集数据和一些坑的总结

    2022-08-23 14:55:54
  • python手写均值滤波

    2022-03-16 20:53:19
  • JavaScript 拾漏补遗

    2024-04-19 09:52:05
  • 详解Go语言中泛型的实现原理与使用

    2024-02-06 08:30:15
  • C#数据导入/导出Excel文件及winForm导出Execl总结

    2023-07-18 04:04:43
  • 贝聿铭写给年轻设计师的十点忠告

    2010-01-24 18:46:00
  • asp之家 网络编程 m.aspxhome.com