typeof 操作符
typeof 操作符(和 instanceof 一起)或許是 JavaScript 中最大的設計缺陷,
因為幾乎不可能從它們那裡得到想要的結果。
儘管 instanceof 還有一些極少數的應用情境,typeof 只有一個實際的應用(譯者註:這個實際應用是用來檢測一個對象是否已經定義或者是否已經賦值),
而這個應用卻不是用來檢查對象的類型。
注意: 由於 typeof 也可以像函數的文法被調用,比如 typeof(obj),但這並是一個函數調用。
那兩個小括弧只是用來計算一個運算式的值,這個傳回值會作為 typeof 操作符的一個運算元。
實際上不存在名為 typeof 的函數。
JavaScript 類型表格
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 操作符的運算結果。可以看到,這個值在大多數情況下都返回 "object"。
Class 一列表示對象的內部屬性 [[Class]] 的值。
JavaScript 標準文檔中定義: [[Class]] 的值只可能是下面字串中的一個:
Arguments, Array, Boolean, Date, Error,
Function, JSON, Math, Number, Object, RegExp, String.
為了擷取對象的 [[Class]],我們需要使用定義在 Object.prototype 上的方法 toString。
對象的類定義
JavaScript 標準文檔只給出了一種擷取 [[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]]值的對象。
Object.prototype.toString 返回一種標準格式字串,所以上例可以通過 slice截取指定位置的字串,如下所示:
Object.prototype.toString.call([]) // "[object Array]"
Object.prototype.toString.call({}) // "[object Object]"
Object.prototype.toString.call(2) // "[object Number]"
ES5 提示: 在 ECMAScript 5 中,為了方便,對 null 和 undefined 調用Object.prototype.toString 方法,
其傳回值由 Object 變成了 Null 和 Undefined。
譯者註:這種變化可以從 IE8 和 Firefox 4 中看出區別,如下所示:
// 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'
上面代碼會檢測 foo 是否已經定義;如果沒有定義而直接使用會導致 ReferenceError 的異常。
這是 typeof 唯一有用的地方。
結論
為了檢測一個對象的類型,強烈推薦使用 Object.prototype.toString 方法;
因為這是唯一一個可依賴的方式。正如上面表格所示,typeof 的一些傳回值在標準文檔中並未定義,
因此不同的引擎實現可能不同。
除非為了檢測一個變數是否已經定義,我們應盡量避免使用 typeof 操作符。