前言
在我们编写js的代码中,要处理各种数据。ECMAScript中有5种简单数据类型(也称为基本数据类型):Undefined
、Null
、Boolean
、Number
和String
,还有1种复杂数据类型——Object
。
面对这6种数据类型,我们应该如何做出准确的判断呢?
typeof运算符
typeof
可以解决大部分的数据类型判断,它是一个一元运算,放在一个运算值之前,其返回值为一个字符串。
以下是各种数据类型返回结果:
var iStr = "JavaScript"; |
从中我们能够发现:
null
、对象和数组都会返回"object"
- 可以使用
typeof
区分null
和undefined
- 函数会返回
"function"
- 暂时无法区分出对象和数组
在IE8和更早版本的IE浏览器中,使用typeof
来检测DOM节点(比如document.getElementById()
)中的函数都返回"object"
。// IE8及以下
typeof document.getElementById; // "object"
typeof document.getElementsByTagName; // "object"
typeof document.createElement; // "object"
instanceof运算符
instanceof
运算符希望左操作数是一个对象,右操作数标识对象的类。如果左侧的对象是右侧类的实例,则表达式返回true
,否则返回false
。
|
使用instanceof
,我们可以区分出对象和数组。
instanceof
是基于实例与类的关系来判断类型的,如果一个页面中有多个<iframe>
,每个<iframe>
下的Object
、Array
、String
等基类都是不同的对象,所以instanceof
不能跨<iframe>
。
constructor属性
constructor
属性返回创建此对象的构造函数的引用。
实际上,一个实例被构造函数创建出来后,其本身是没有constructor
属性的,其找到的constructor
属性其实是这个实例的原型(通过__proto__
访问)下的一个属性。
var obj = {}; |
所以我们可以想到constructor
属性只能用于判断该实例的构造函数的引用,不能像instanceof
那样判断该实例所有的类。
var arr = []; // 新建一个名为arr的数组 |
不过该实例的原型对象下的constructor
属性是不可靠的,一旦constructor
属性被修改或者原型对象被重写,就会触发异常。
var arr = []; // 新建一个名为arr的数组 |
通过上面的测试可以看出,就算constructor
属性被修改了,instanceof
的判断依然是可靠的。
Object.prototype.toString方法
最后介绍一种通用,而且又是最精确的方法。
// 将该方法封装成一个函数 |
实际上,这个方法显示调用了Object.toString()
,返回一个表示该对象的字符串。通过判断返回的字符串(大小写不能写错)就能知道是不是我们想要的数据类型。并且这种方法可以跨<iframe>
,因为该方法与实例和类的关系无关。
在IE8版本以下null
和undefined
的结果是"[object Object]"
。// IE8
Object.prototype.toString.call(null); // "[object Object]"
Object.prototype.toString.call(undefined); // "[object Object]"
总结
介绍了四种判断数据类型的方法,最后我来做个比较总结:
typeof
- 优点
- 能判断大部分的数据类型
- 运算符的速度快
- 能判断
null
和undefined
- 缺点
null
、对象和数组的返回结果都是"object"
- 无法进一步判断对象和数组
- 优点
instanceof
- 优点
- 能判断该实例所有的类,可靠
- 运算符的速度快
- 能进一步判断对象和数组
- 缺点
- 无法跨
<iframe>
判断
- 无法跨
- 优点
constructor
- 优点
- 实际上是判断该实例原型下的
constructor
属性
- 实际上是判断该实例原型下的
- 缺点
- 如果原型下的
constructor
属性被修改,结果不可靠 - 因为查找的是属性,所以比运算符的速度慢
- 如果原型下的
- 优点
Object.prototype.toString
- 优点
- 实际上是显示调用Object.toString()
- 通用,所有数据类型都可以精确区分
- 能够跨
<iframe>
判断
- 缺点
- 因为调用的是方法,所以速度最慢
- 优点
Object.prototype.toString
虽然通用,不过性能最差,我是只有在其他方法解决不了的情况下,才会选用它。以上方法需要根据需求,灵活使用,以求代码性能的最大化。