javascript如何判断变量的数据类型

本文深入探讨JavaScript中的类型检测方法,包括typeof、instanceof、Object.prototype.toString.call及constructor等的使用和局限性,并提供了综合判断方案。

typeof

用法示例

var arr = [];
typeof arr;    //'object'
typeof(arr);    //'object'

typeof实际上是一个一元运算符,因此可以用上述代码所示的两种用法。

typeof所支持的数据类型

clipboard.png

从上表可以看出,typeof支持的数据类型还是比较齐全的,除了俩比较特殊以外:

  • Null使用typeof返回object,这跟我们的认知还是有一定差距的,这是javascript的一个设计上的bug,ECMAScript 6中有提议修改此bug,但已经被否决了;不过只要加个逻辑非!运算符,就能把Null这种情况给排除了。
  • 除了function以外,其它具体的对象类型都无法判断出来。

typeof浏览器兼容性注意点

对正则表达式字面量的类型判断在某些浏览器中不符合标准:
typeof /s/ === 'function'; // Chrome 1-12 , 不符合 ECMAScript 5.1
typeof /s/ === 'object'; // Firefox 5+ , 符合 ECMAScript 5.1
IE 宿主对象是对象而不是函数

在 IE 6, 7 和 8 中,大多数的宿主对象是对象,而不是函数,例如:

typeof alert === 'object'

instanceof

用法示例

// 定义构造函数
function C(){} 
function D(){} 

var o = new C();

// true,因为 Object.getPrototypeOf(o) === C.prototype
o instanceof C; 

// false,因为 D.prototype不在o的原型链上
o instanceof D; 

o instanceof Object; // true,因为Object.prototype.isPrototypeOf(o)返回true

instanceof是一个二元运算符。

instanceof总结

  • javascript中的原生对象以及用户的自定义对象基本上都能利用instanceof识别出来,除了NullUndefined
  • instanceof无法区分开同一原型继承链:
function A(){
    //...
}

function B(){
    //...
}

function C(){
    //...
}

var a = new A();
B.prototype = a;

var b = new B();
C.prototype = b;

var c = new C();

c instanceof A;    //true
c instanceof B;    //true
c instanceof C;    //true

Object.prototype.toString.call

用法示例

function type(obj) {
  return Object.prototype.toString.call(obj).slice(8, -1);
}
type(1);    //"Number"
type("1");    //"String"
type(true);    //"Boolean"
type(undefined);    //"Undefined"
type(null);    //"Null"
type({});    //"Object"
type([]);    //"Array"
type(new Date);    //"Date"
type(/\d/);    //"RegExp"
type(function() {});    //"Function"

function Point(x, y) {
    //
}
type(new Point(1, 2));    //"Object"

用法解析

从以上用法示例可以看出,这个基于Object.prototype.toString.call封装好的函数用法跟typeof非常相似,但是在支持的数据类型上比typeof强多了,所有的javascript原生数据类型都能判断出来。遗憾的是,Object.prototype.toString.call也不是万能的方案:无法识别自定义的对象类型。
Object.prototype.toString.call实际上是返回这样形式的值:

Object.prototype.toString.call(1);    //'[object Number]'
Object.prototype.toString.call('1');    //'[object String]'

因此只要用slice方法把数据类型“切”出来就成了。

constructor(构造函数)

用法示例

/*
* 获取对象构造函数名称
*/
function getConstructorName(obj){
    return obj && obj.constructor && obj.constructor.toString().match(/function\s*([^(]*)/)[1]; //利用obj && obj.constructor来判断null和undefined
}

用法解析

这是一种非常巧妙的判断数据类型的方法——利用构造函数判断数据类型,这是基于javascript的特性/规范:

  • 对象的构造函数名就是该数据类型。
  • NullUndefined外,所有的数据类型都是/可以转化为对象,而如果是对象,就肯定有构造函数。

特性

  1. 因为NullUndefined没有构造函数,因此不能用此方法来判断。
  2. 由于同一条原型继承链上的各个对象的构造函数都不一样,因此,此方法可以区分开继承链上的各个自定义数据类型。
function A(){
    //...
}

function B(){
    //...
}

function C(){
    //...
}

var a = new A();
B.prototype = a;

var b = new B();
C.prototype = b;

var c = new C();

getConstructorName(a);    //A
getConstructorName(b);    //B
getConstructorName(c);    //C

总结

以上这四种方法都有不同程度的缺陷,如果从实用性的角度来考虑,可以综合一下:

function type(obj) {console.dir(obj);
  if(!obj) {
    return Object.prototype.toString.call(obj).slice(8, -1);
  }
  return obj.constructor.toString().match(/function\s*([^(]*)/)[1];
}
var t = type(1) // t==="number"
var t = type(new Number(1)) // t==="number"
var t = type("abc") // t==="string"
var t = type(new String("abc")) // t==="string"
var t = type(true) // t==="boolean"
var t = type(undefined) // t==="undefined"
var t = type(null) // t==="null"
var t = type({}) // t==="object"
var t = type([]) // t==="array"
var t = type(new Date) // t==="date"
var t = type(/\d/) // t==="regexp"
var t = type(function(){}) // t==="function"

参考资料

typeof - JavaScript | MDN
instanceof - JavaScript | MDN

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值