js中typeof的用法彙總
這篇文章主要是對js中typeof的用法進行了詳細的彙總介紹,需要的朋友可以過來參考下,希望對大家有所幫助
JavaScript中的typeof其實非常複雜,它可以用來做很多事情,但同時也有很多怪異的表現.本文列舉出了它的多個用法,而且還指出了存在的問題以及解決辦法.
> typeof undefined
'undefined'
> typeof null // well-known bug
'object'
> typeof true
'boolean'
> typeof 123
'number'
> typeof "abc"
'string'
> typeof function() {}
'function'
> typeof {}
'object'
> typeof []
'object'
> typeof unknownVariable
'undefined'
1.檢查一個變數是否存在,是否有值.
typeof在兩種情況下會返回”undefined”:一個變數沒有被宣告的時候,和一個變數的值是undefined的時候.例如:
typeof undeclaredVariable === “undefined” true > var declaredVariable; > typeof declaredVariable ‘undefined’ > typeof undefined ‘undefined’
還有其他辦法檢測某個值是否是undefined:var value = undefined; > value === undefined true
但這種方法如果使用在一個未宣告的變數上的時候,就會丟擲異常,因為只有typeof才可以正常檢測未宣告的變數的同時還不報錯:undeclaredVariable === undefined ReferenceError: undeclaredVariable is not defined
注意:未初始化的變數,沒有被傳入引數的形參,不存在的屬性,都不會出現上面的問題,因為它們總是可訪問的,值總是undefined:var declaredVariable; > declaredVariable === undefined true > (function (x) { return x === undefined }()) true > ({}).foo === undefined true
譯者注:因此,如果想檢測一個可能沒有被宣告的全域性變數是否存在,也可以使用 if(window.maybeUndeclaredVariable){}
問題: typeof在完成這樣的任務時顯得很繁雜.
解決辦法: 這樣的操作不是很常見,所以有人覺的沒必要再找更好的解決辦法了.不過也許有人會提出一個專門的操作符:
defined undeclaredVariable false > var declaredVariable; > defined declaredVariable false
或者,也許有人還需要一個檢測變數是否被宣告的操作符:declared undeclaredVariable false > var declaredVariable; > declared declaredVariable true
譯者注:在perl裡,上面的defined操作符相當於defined(),上面的declared操作符相當於exists(),
2.判斷一個值不等於undefined也不等於null
問題:如果你想檢測一個值是否被定義過(值不是undefined也不是null),那麼你就遇到了typeof最有名的一個怪異表現(被認為是一個bug):typeof null返回了”object”:
typeof null ‘object’
譯者注:這隻能說是最初的JavaScript實現的bug,而現在標準就是這樣規範的.V8曾經修正並實現過typeof null === “null”,但最終證明不可行.http://wiki.ecmascript.org/doku.php?id=harmony:typeof_null
解決辦法: 不要使用typeof來做這項任務,用下面這樣的函式來代替:
function isDefined(x) { return x !== null && x !== undefined; }
另一個可能性是引入一個“預設值運算子”,在myValue未定義的情況下,下面的表示式會返回defaultValue:
myValue ?? defaultValue
上面的表示式等價於:
(myValue !== undefined && myValue !== null) ? myValue : defaultValue
又或者:
myValue ??= defaultValue
其實是下面這條語句的簡化:
myValue = myValue ?? defaultValue
當你訪問一個巢狀的屬性時,比如bar,你或許會需要這個運算子的幫助:
obj.foo.bar
如果obj或者obj.foo是未定義的,上面的表示式會丟擲異常.一個運算子.??可以讓上面的表示式在遍歷一層一層的屬性時,返回第一個遇到的值為undefined或null的屬性:
obj.??foo.??bar
上面的表示式等價於:
(obj === undefined || obj === null) ? obj : (obj.foo === undefined || obj.foo === null) ? obj.foo : obj.foo.bar
3.區分物件值和原始值
下面的函式用來檢測x是否是一個物件值:
function isObject(x) { return (typeof x === “function” || (typeof x === “object” && x !== null)); }
問題: 上面的檢測比較複雜,是因為typeof把函式和物件看成是不同的型別,而且typeof null返回”object”.
解決辦法: 下面的方法也經常用於檢測物件值:
function isObject2(x) { return x === Object(x); }
警告:你也許認為這裡可以使用instanceof Object來檢測,但是instanceof是通過使用使用一個物件的原型來判斷例項關係的,那麼沒有原型的物件怎麼辦呢:
var obj = Object.create(null); > Object.getPrototypeOf(obj) null
obj確實是一個物件,但它不是任何值的例項:typeof obj ‘object’ > obj instanceof Object false
在實際中,你可能很少遇到這樣的物件,但它的確存在,而且有它的用途.
譯者注:Object.prototype就是一個預設存在的,沒有原型的物件
Object.getPrototypeOf(Object.prototype)null>typeof Object.prototype’object’>Object.prototype instanceof Object false
4.原始值的型別是什麼?
typeof是最好的用來檢視某個原始值的型別的方式.
typeof “abc” ‘string’ > typeof undefined ‘undefined’
問題: 你必須知道typeof null的怪異表現.typeof null // 要小心! ‘object’
解決辦法: 下面的函式可以修復這個問題(只針對這個用例).
function getPrimitiveTypeName(x) { var typeName = typeof x; switch(typeName) { case “undefined”: case “boolean”: case “number”: case “string”: return typeName; case “object”: if (x === null) { return “null”; } default: // 前面的判斷都沒通過 throw new TypeError(“引數不是一個原始值: “+x); } }
更好的解決辦法: 實現一個函式getTypeName(),除了可以返回原始值的的型別,還可以返回物件值的內部[[Class]]屬性.這裡講了如何實現這個函式(譯者注:jQuery中的$.type就是這樣的實現)
5.某個值是否是函式
typeof可以用來檢測一個值是否是函式.> typeof function () {} ‘function’ > typeof Object.prototype.toString ‘function’
原則上說,instanceof Function也可以進行這種需求的檢測.乍一看,貌似寫法還更加優雅.但是,瀏覽器有一個怪癖:每一個框架和視窗都有它自己的全域性變數.因此,如果你將某個框架中的物件傳到另一個框架中,instanceof就不能正常工作了,因為這兩個框架有著不同的建構函式.這就是為什麼ECMAScript5中會有Array.isArray()方法的原因.如果有一個能夠跨框架的,用於檢查一個物件是否是給定的建構函式的例項的方法的話,那會很好.上述的getTypeName()是一個可用的變通方法,但也許還有一個更根本的解決方案.
6.綜述
下面提到的,應該是目前JavaScript中最迫切需要的,可以代替一些typeof目前職責的功能特性:
isDefined() (比如Object.isDefined()): 可以作為一個函式或者一個運算子
isObject()
getTypeName()
能夠跨框架的,檢測一個物件是否是指定的建構函式的例項的機制
檢查某個變數是否已經被宣告這樣的需求,可能沒那麼必要有自己的運算子.