typeof
操作符(还有 instanceof
)可能是 Javascript
设计中最大缺陷,因为它几乎是完全破损的。由于 typeof
用法与调用函数的语法相似,因此常被误以为是函数调用,实际上并不存在名为 typeof
的函数,typeof
只是一个操作符而已。
尽管 instanceof
仍然还有少数的应用场景,typeof
则只有一个实际的用途,但这个用途不能用来检测对象的类型。
类型表格
Value Class Type
-------------------------------------
"foo" String string
new String("foo") String object
1.2 Number number
new Number(1.2) Number object
true Boolean boolean
new Boolean(true) Boolean object
new Date() Date object
new Error() Error object
[1,2,3] Array object
new Array(1, 2, 3) Array object
new Function("") Function function
/abc/g RegExp object (function in Nitro/V8)
new RegExp("meow") RegExp object (function in Nitro/V8)
{} Object object
new Object() Object object
在上述表格中,Type
列表示 typeof
操作符的结果。而 Class
列则表示对象内部的 [[Class]]
属性。
为了获得 [[Class]]
属性,我们需要使用 Object.prototype
的 toString
方法。
Class 属性
文档中明确地给出了获得 [[Class]]
属性的途径,就是使用 Object.prototype.toString
。
function is(type, obj) {
var clas = Object.prototype.toString.call(obj).slice(8, -1);
return obj !== undefined && obj !== null && clas === type;
}
is('String', 'test'); // true
is('String', new String('test')); // true
上例中,Object.prototype.toString
被调用,this
被设置指向需要获取其 [[Class]]
属性值的对象。
文档定义:
[[Class]]
属性的值只可能是下列字符串:Arguments, Array, Boolean, Date, Error, Function, JSON, Math, Number, Object, RegExp, String
。
对null
和undefined
调用Object.prototype.toString
方法时, 其返回值将由Object
变成了Null
和Undefined
。
测试变量是否定义
typeof foo !== 'undefined'
上述语句将会测试变量 foo
已定义与否,如果未定义而引用 foo
将会抛出 ReferenceError
错误,这实际上是 typeof
用处最大的地方。
总结
为了检测一个对象的类型,最可靠的方法就是使用 Object.prototype.toString
,正如第一个表格上的内容,typeof
操作符并不能返回确切的对象类型,但是我们可以使用 typeof
操作符经常会被用来判断变量是否定义。
其实 typeof
操作符还可以被用来测试变量是否为函数,@humphry 前辈的回答进一步丰富了 typeof
的用途: