js中typeof的用法匯總
JavaScript中的typeof其實(shí)非常復(fù)雜,它可以用來(lái)做很多事情,但同時(shí)也有很多怪異的表現(xiàn).本文列舉出了它的多個(gè)用法,而且還指出了存在的問題以及解決辦法.
> 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.檢查一個(gè)變量是否存在,是否有值.
typeof在兩種情況下會(huì)返回"undefined":一個(gè)變量沒有被聲明的時(shí)候,和一個(gè)變量的值是undefined的時(shí)候.例如:
> typeof undeclaredVariable === "undefined" true > var declaredVariable; > typeof declaredVariable 'undefined' > typeof undefined 'undefined'
還有其他辦法檢測(cè)某個(gè)值是否是undefined:
> var value = undefined; > value === undefined true
但這種方法如果使用在一個(gè)未聲明的變量上的時(shí)候,就會(huì)拋出異常,因?yàn)橹挥衪ypeof才可以正常檢測(cè)未聲明的變量的同時(shí)還不報(bào)錯(cuò):
> undeclaredVariable === undefined ReferenceError: undeclaredVariable is not defined
注意:未初始化的變量,沒有被傳入?yún)?shù)的形參,不存在的屬性,都不會(huì)出現(xiàn)上面的問題,因?yàn)樗鼈兛偸强稍L問的,值總是undefined:
> var declaredVariable; > declaredVariable === undefined true > (function (x) { return x === undefined }()) true > ({}).foo === undefined true
譯者注:因此,如果想檢測(cè)一個(gè)可能沒有被聲明的全局變量是否存在,也可以使用 if(window.maybeUndeclaredVariable){}
問題: typeof在完成這樣的任務(wù)時(shí)顯得很繁雜.
解決辦法: 這樣的操作不是很常見,所以有人覺的沒必要再找更好的解決辦法了.不過(guò)也許有人會(huì)提出一個(gè)專門的操作符:
> defined undeclaredVariable false > var declaredVariable; > defined declaredVariable false
或者,也許有人還需要一個(gè)檢測(cè)變量是否被聲明的操作符:
> declared undeclaredVariable false > var declaredVariable; > declared declaredVariable true
譯者注:在perl里,上面的defined操作符相當(dāng)于defined(),上面的declared操作符相當(dāng)于exists(),
2.判斷一個(gè)值不等于undefined也不等于null
問題:如果你想檢測(cè)一個(gè)值是否被定義過(guò)(值不是undefined也不是null),那么你就遇到了typeof最有名的一個(gè)怪異表現(xiàn)(被認(rèn)為是一個(gè)bug):typeof null返回了"object":
> typeof null 'object'
譯者注:這只能說(shuō)是最初的JavaScript實(shí)現(xiàn)的bug,而現(xiàn)在標(biāo)準(zhǔn)就是這樣規(guī)范的.V8曾經(jīng)修正并實(shí)現(xiàn)過(guò)typeof null === "null",但最終證明不可行.http://wiki.ecmascript.org/doku.php?id=harmony:typeof_null
解決辦法: 不要使用typeof來(lái)做這項(xiàng)任務(wù),用下面這樣的函數(shù)來(lái)代替:
function isDefined(x) { return x !== null && x !== undefined; }
另一個(gè)可能性是引入一個(gè)“默認(rèn)值運(yùn)算符”,在myValue未定義的情況下,下面的表達(dá)式會(huì)返回defaultValue:
myValue ?? defaultValue
上面的表達(dá)式等價(jià)于:
(myValue !== undefined && myValue !== null) ? myValue : defaultValue
又或者:
myValue ??= defaultValue
其實(shí)是下面這條語(yǔ)句的簡(jiǎn)化:
myValue = myValue ?? defaultValue
當(dāng)你訪問一個(gè)嵌套的屬性時(shí),比如bar,你或許會(huì)需要這個(gè)運(yùn)算符的幫助:
obj.foo.bar
如果obj或者obj.foo是未定義的,上面的表達(dá)式會(huì)拋出異常.一個(gè)運(yùn)算符.??可以讓上面的表達(dá)式在遍歷一層一層的屬性時(shí),返回第一個(gè)遇到的值為undefined或null的屬性:
obj.??foo.??bar
上面的表達(dá)式等價(jià)于:
(obj === undefined || obj === null) ? obj : (obj.foo === undefined || obj.foo === null) ? obj.foo : obj.foo.bar
3.區(qū)分對(duì)象值和原始值
下面的函數(shù)用來(lái)檢測(cè)x是否是一個(gè)對(duì)象值:
function isObject(x) { return (typeof x === "function" || (typeof x === "object" && x !== null)); }
問題: 上面的檢測(cè)比較復(fù)雜,是因?yàn)閠ypeof把函數(shù)和對(duì)象看成是不同的類型,而且typeof null返回"object".
解決辦法: 下面的方法也經(jīng)常用于檢測(cè)對(duì)象值:
function isObject2(x) { return x === Object(x); }
警告:你也許認(rèn)為這里可以使用instanceof Object來(lái)檢測(cè),但是instanceof是通過(guò)使用使用一個(gè)對(duì)象的原型來(lái)判斷實(shí)例關(guān)系的,那么沒有原型的對(duì)象怎么辦呢:
> var obj = Object.create(null); > Object.getPrototypeOf(obj) null
obj確實(shí)是一個(gè)對(duì)象,但它不是任何值的實(shí)例:
> typeof obj 'object' > obj instanceof Object false
在實(shí)際中,你可能很少遇到這樣的對(duì)象,但它的確存在,而且有它的用途.
譯者注:Object.prototype就是一個(gè)默認(rèn)存在的,沒有原型的對(duì)象
>Object.getPrototypeOf(Object.prototype)null>typeof Object.prototype'object'>Object.prototype instanceof Object false
4.原始值的類型是什么?
typeof是最好的用來(lái)查看某個(gè)原始值的類型的方式.
> typeof "abc" 'string' > typeof undefined 'undefined'
問題: 你必須知道typeof null的怪異表現(xiàn).
> typeof null // 要小心! 'object'
解決辦法: 下面的函數(shù)可以修復(fù)這個(gè)問題(只針對(duì)這個(gè)用例).
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: // 前面的判斷都沒通過(guò) throw new TypeError("參數(shù)不是一個(gè)原始值: "+x); } }
更好的解決辦法: 實(shí)現(xiàn)一個(gè)函數(shù)getTypeName(),除了可以返回原始值的的類型,還可以返回對(duì)象值的內(nèi)部[[Class]]屬性.這里講了如何實(shí)現(xiàn)這個(gè)函數(shù)(譯者注:jQuery中的$.type就是這樣的實(shí)現(xiàn))
5.某個(gè)值是否是函數(shù)
typeof可以用來(lái)檢測(cè)一個(gè)值是否是函數(shù).> typeof function () {} 'function' > typeof Object.prototype.toString 'function'
原則上說(shuō),instanceof Function也可以進(jìn)行這種需求的檢測(cè).乍一看,貌似寫法還更加優(yōu)雅.但是,瀏覽器有一個(gè)怪癖:每一個(gè)框架和窗口都有它自己的全局變量.因此,如果你將某個(gè)框架中的對(duì)象傳到另一個(gè)框架中,instanceof就不能正常工作了,因?yàn)檫@兩個(gè)框架有著不同的構(gòu)造函數(shù).這就是為什么ECMAScript5中會(huì)有Array.isArray()方法的原因.如果有一個(gè)能夠跨框架的,用于檢查一個(gè)對(duì)象是否是給定的構(gòu)造函數(shù)的實(shí)例的方法的話,那會(huì)很好.上述的getTypeName()是一個(gè)可用的變通方法,但也許還有一個(gè)更根本的解決方案.
6.綜述
下面提到的,應(yīng)該是目前JavaScript中最迫切需要的,可以代替一些typeof目前職責(zé)的功能特性:
isDefined() (比如Object.isDefined()): 可以作為一個(gè)函數(shù)或者一個(gè)運(yùn)算符
isObject()
getTypeName()
能夠跨框架的,檢測(cè)一個(gè)對(duì)象是否是指定的構(gòu)造函數(shù)的實(shí)例的機(jī)制
檢查某個(gè)變量是否已經(jīng)被聲明這樣的需求,可能沒那么必要有自己的運(yùn)算符.
相關(guān)文章
js關(guān)閉當(dāng)前頁(yè)面(窗口)的幾種方式總結(jié)
js關(guān)閉當(dāng)前頁(yè)面(窗口)的幾種方式總結(jié),需要的朋友可以參考一下2013-03-03微信小程序scroll-view的滾動(dòng)條設(shè)置實(shí)現(xiàn)
這篇文章主要介紹了微信小程序scroll-view的滾動(dòng)條設(shè)置實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03bootstrap的3級(jí)菜單樣式,支持母版頁(yè)保留打開狀態(tài)實(shí)現(xiàn)方法
下面小編就為大家?guī)?lái)一篇bootstrap的3級(jí)菜單樣式,支持母版頁(yè)保留打開狀態(tài)實(shí)現(xiàn)方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-11-11uniapp中使用vuex的過(guò)程(解決uniapp無(wú)法在data和template中獲取vuex數(shù)據(jù)問題)
這篇文章主要介紹了uniapp中使用vuex(解決uniapp無(wú)法在data和template中獲取vuex數(shù)據(jù)問題),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-05-05bootstrap-table實(shí)現(xiàn)服務(wù)器分頁(yè)的示例 (spring 后臺(tái))
本篇文章主要介紹了bootstrap-table實(shí)現(xiàn)服務(wù)器分頁(yè)的示例 (spring 后臺(tái)),具有一定的參考價(jià)值,有興趣的可以了解一下2017-09-09JS在IE和FF下attachEvent,addEventListener學(xué)習(xí)筆記
今天小弄了一下JS事件,主要說(shuō)一下FF和IE兼容的問題2009-11-11教你修改element-ui源碼給el-dialog添加全屏功能
el-dialog組件提供了fullscreen功能,但是無(wú)法滿足業(yè)務(wù)需求。系統(tǒng)使用了許多dialog,不方便重新封裝dialog組件,故直接對(duì)源碼進(jìn)行修改,這篇文章主要介紹了修改element-ui源碼給el-dialog添加全屏功能,需要的朋友可以參考下2022-11-11es6數(shù)組的flat(),flatMap()函數(shù)用法實(shí)例分析
這篇文章主要介紹了es6數(shù)組的flat(),flatMap()函數(shù)用法,結(jié)合實(shí)例形式分析了es6數(shù)組的flat(),flatMap()函數(shù)基本功能、使用方法及操作注意事項(xiàng),需要的朋友可以參考下2020-04-04JS實(shí)現(xiàn)動(dòng)態(tài)給標(biāo)簽控件添加事件的方法示例
這篇文章主要介紹了JS實(shí)現(xiàn)動(dòng)態(tài)給標(biāo)簽控件添加事件的方法,結(jié)合實(shí)例形式分析了javascript簡(jiǎn)單實(shí)現(xiàn)動(dòng)態(tài)添加事件的相關(guān)操作技巧,需要的朋友可以參考下2017-05-05