typeof 操作符(和instanceof一起)或許是 JavaScript 中最大的設(shè)計(jì)缺陷,
因?yàn)閹缀醪豢赡軓乃鼈兡抢锏玫较胍慕Y(jié)果。
盡管 instanceof 還有一些極少數(shù)的應(yīng)用場景,typeof 只有一個(gè)實(shí)際的應(yīng)用(譯者注:這個(gè)實(shí)際應(yīng)用是用來檢測一個(gè)對(duì)象是否已經(jīng)定義或者是否已經(jīng)賦值),
而這個(gè)應(yīng)用卻不是用來檢查對(duì)象的類型。
注意: 由于
typeof也可以像函數(shù)的語法被調(diào)用,比如typeof(obj),但這并不是一個(gè)函數(shù)調(diào)用。 那兩個(gè)小括號(hào)只是用來計(jì)算一個(gè)表達(dá)式的值,這個(gè)返回值會(huì)作為typeof操作符的一個(gè)操作數(shù)。 實(shí)際上不存在名為typeof的函數(shù)。
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 操作符的運(yùn)算結(jié)果??梢钥吹剑@個(gè)值在大多數(shù)情況下都返回 "object"。
Class 一列表示對(duì)象的內(nèi)部屬性 [[Class]] 的值。
JavaScript 標(biāo)準(zhǔn)文檔中定義:
[[Class]]的值只可能是下面字符串中的一個(gè):Arguments,Array,Boolean,Date,Error,Function,JSON,Math,Number,Object,RegExp,String.
為了獲取對(duì)象的 [[Class]],我們需要使用定義在 Object.prototype 上的方法 toString。
JavaScript 標(biāo)準(zhǔn)文檔只給出了一種獲取 [[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 方法被調(diào)用,this 被設(shè)置為了需要獲取 [[Class]] 值的對(duì)象。
譯者注:Object.prototype.toString 返回一種標(biāo)準(zhǔn)格式字符串,所以上例可以通過 slice 截取指定位置的字符串,如下所示:
Object.prototype.toString.call([]) // "[object Array]"
Object.prototype.toString.call({}) // "[object Object]"
Object.prototype.toString.call(2) // "[object Number]"
ES5 提示: 在 ECMAScript 5 中,為了方便,對(duì)
null和undefined調(diào)用Object.prototype.toString方法, 其返回值由Object變成了Null和Undefined。
譯者注:這種變化可以從 IE8 和 Firefox 4 中看出區(qū)別,如下所示:
// IE8
Object.prototype.toString.call(null) // "[object Object]"
Object.prototype.toString.call(undefined) // "[object Object]"
// Firefox 4
Object.prototype.toString.call(null) // "[object Null]"
Object.prototype.toString.call(undefined) // "[object Undefined]"
typeof foo !== 'undefined'
上面代碼會(huì)檢測 foo 是否已經(jīng)定義;如果沒有定義而直接使用會(huì)導(dǎo)致 ReferenceError 的異常。
這是 typeof 唯一有用的地方。
為了檢測一個(gè)對(duì)象的類型,強(qiáng)烈推薦使用 Object.prototype.toString 方法;
因?yàn)檫@是唯一一個(gè)可依賴的方式。正如上面表格所示,typeof 的一些返回值在標(biāo)準(zhǔn)文檔中并未定義,
因此不同的引擎實(shí)現(xiàn)可能不同。
除非為了檢測一個(gè)變量是否已經(jīng)定義,我們應(yīng)盡量避免使用 typeof 操作符。