判断变量是某种数据类型也是实际开发中常见的操作,总结如下:
写在前面
在介绍这两者之前先来回顾下js中的数据类型都有哪些。
- 基础数据类型
- null
- undefined
- String
- Number
- Boolean
- 引用数据类型
- Object、Array、Function、Date等
typeof
typeof操作符返回一个字符串,我们先来看看使用typeof判断数据类型的结果
typeof 10 // 'number'
typeof Number(10) // 'number'
typeof NaN // 'number'
typeof Infinity // 'number'
typeof 'hello' // 'string'
typeof String('hello') // 'string'
typeof '' // 'string'
typeof (typeof 10) // 'string'
typeof true // 'boolean'
typeof Boolean(true) // 'boolean'
typeof undefined // 'undefined'
typeof [1,2,3] // 'object'
typeof {name: 'tom'} // 'object'
typeof new String('hello') // 'object'
typeof new Number(10) // 'object'
typeof new Boolean(true) // 'object'
typeof function(){} // 'function'
typeof class C{} // 'function'
typeof Math.sin // 'function'
typeof new Function() // 'function'
typeof /s/ // 'function'; Chrome 1-12 , 不符合 ECMAScript 5.1
typeof /s/ // 'object'; Firefox 5+ , 符合 ECMAScript 5.1
这是一个例外
typeof document.all // 'undefined';
可以看出typeof对于基本数据类型的判断是值得信赖的,但是对于引用类型来讲并不是很友好,这里要特别说明一种情况:
typeof null // 'object'
按照上述的逻辑来讲应该 也是null才对,官方给出的解释是:
在 JavaScript 最初的实现中,JavaScript 中的值是由一个表示类型的标签和实际数据值表示的。对象的类型标签是 0。由于 null 代表的是空指针(大多数平台下值为 0x00),因此,null的类型标签也成为了 0,typeof null就错误的返回了"object"。
小结: 对于基本数据类型和function类型可以使用typeof来判断,对于引用类型的判断不是很精确。
instanceof
使用方法: instance instanceof constructor
判断规则: 判断constructor.prototype是否在instance的原型链上
// 定义构造函数
function C(){}
function D(){}
var o = new C();
o instanceof C; // true,因为 Object.getPrototypeOf(o) === C.prototype
o instanceof D; // false,因为 D.prototype不在o的原型链上
o instanceof Object; // true,因为Object.prototype.isPrototypeOf(o)返回true
C.prototype instanceof Object // true,同上
C.prototype = {};
var o2 = new C();
o2 instanceof C; // true
o instanceof C; // false,C.prototype指向了一个空对象,这个空对象不在o的原型链上.
D.prototype = new C(); // 继承
var o3 = new D();
o3 instanceof D; // true
o3 instanceof C; // true 因为C.prototype现在在o3的原型链上
var str = new String('hello')
str instanceof String // true
str instanceof Object // true
这里有一个特例
var foo = function(){};
foo instanceof Object // true
foo instanceof Function // true
其实查看原型链的‘家谱图’后也不难解释。
对于引用类型的判断还是很友好的但是对于基本类型的判断就不是很友好了:
var test = 'hello', num = 100;
test instanceof String // false
num instanceof Number // false
test instanceof Object // false
num instanceof Object // false
这里有一种情况需要注意:
在浏览器中,我们的脚本可能需要在多个窗口之间进行交互。多个窗口意味着多个全局环境,不同的全局环境拥有不同的全局对象,从而拥有不同的内置类型构造函数。这可能会引发一些问题。比如,表达式 [] instanceof window.frames[0].Array 会返回false,因为 Array.prototype !== window.frames[0].Array.prototype
小结: 对于引用类型可以使用instanceof来判断,对于基础数据类型的判断不是很精确。
这时我们需要一种无论对于基本数据类型还是引用类型都可以精确判断的方法:
Object.prototype.toString.call('hello') // "[object String]"
Object.prototype.toString.call(100) // "[object Number]"
Object.prototype.toString.call(null) // "[object Null]"
Object.prototype.toString.call(undefined) // "[object Undefined]"
Object.prototype.toString.call([1,2,3]) // "[object Array]"
...
这种方法是最精确的判断数据类型的方法。