詳解在JavaScript中如何判斷變量類型
JavaScript是一個動態(tài)類型語言,在運行時獲取變量類型是常用操作,由于JavaScript設計的問題,看似簡單的問題,在JavaScript中可能并不簡單,比如在社區(qū)中流傳的下圖,仔細看一下這些坑,即便是JavaScript老司機也經(jīng)常翻車。
上圖中typeof NaN
會返回number
,這可能和你想的不一樣,在JavaScript準確的獲取變量類型,并不簡單,正因為如此,這個問題經(jīng)常被用來考察面試者,由于程序=數(shù)據(jù)+算法,而基本數(shù)據(jù)是數(shù)據(jù)的基礎,所以面試中考察類型也是合理的。
如果面試中你只回答使用typeof獲取類型,那大概率是會減分的,那么該如何回答這道題呢?本文將全面系統(tǒng)的介紹如何在JavaScript中判斷類型,閱讀本文,可以幫你,在工作中,避開類型判斷雷區(qū),如果在面試中你回答本文的內(nèi)容,那么面試官將驚呼,這是高手,比我知道的都多,然后自然是好評嘍。
下面先從最簡單的例子開始,并一步一步提升難度,擴展思路,先來看第一個例子:
在工作中,對于數(shù)據(jù)為空的情況,經(jīng)常要做防御式編程,誤區(qū)之一是使用非運算符直接判斷。但這樣做是可能有坑的,比如這會把很多徦值計算在內(nèi),常見的徦值有0
, ''
, false
, null
, undefined
等。例如如下的double函數(shù),需要對參數(shù)做為空的防御,這里使用非空運算符。
function double(x) { // 0會被錯誤計算 if (!x) { return NaN; } return x * 2; }
對于判空,另一種寫法是直接和null
和undefined
作比較,示例如下:
if (x === null || x === undefined) { return NaN; }
雖然邏輯看起來非常正確,但這種寫法有一個比較嚴重的問題,在JavaScript中undefined
并不是關鍵字,而是 window上的一個屬性,在 ECMAScript 5 之前這個屬性可寫的,如果undefined
被重新復制,在過時瀏覽器中會導致判斷失效,示例如下:
window.undefined = 1; // 判斷不能生效 if (x === undefined) { console.log(111); }
雖然在現(xiàn)代瀏覽器中不會有這個 bug,但是如果文法作用域中存在名字為undefined
的變量還是會有問題,這被稱作undefiined
變量覆蓋,例如如下代碼中,undefined
被1覆蓋了。
(function () { var undefined = 1; // 判斷不能生效 if (x === undefined) { console.log(111); } })();
關于判空還有比較巧妙的方法,可以只和null
判斷相等,借助隱式轉換達到同樣的效果,null
是關鍵字,沒有undefined
的問題。
// null 和 undefined都會判斷 if (x == null) { }
在全等是最佳實踐的背景下,這種做法并不被鼓勵,建議使用 typeof 來判斷undefined
,typeof 通過內(nèi)部類型判斷,不存在undefined
變量覆蓋的問題。
if (x === null || typeof x === 'undefined') { }
對于 number 類型,有個需要注意的地方,在 JavaScript 中有個特殊的值叫做 NaN,NaN 的類型也是 number,編碼中很少直接使用到 NaN,通常都是在計算失敗時會得到這個值。
但將 NaN 作為 number 使用時就會報錯,比如調用 NaN 上的toFixed
方法,更好的做法是添加 isNaN 的判斷,需要注意 number 類型的特殊邏輯。
const x = Math.sqrt(-1); // NaN // 注意這里的isNaN判斷 if (typeof x === 'number' && !isNaN(x)) { console.log(x.toFixed(2)); }
也可以使用 ECMAScript 2015 新增的Number.isNaN
,和全局函數(shù) isNaN 的區(qū)別是,Number.isNaN 不會自行將參數(shù)轉換成數(shù)字,Number.isNaN
的邏輯下面的代碼類似,Number.isNaN
是更好的建議,但是需要注意兼容性的問題
Number.isNaN = function (value) { return typeof value === 'number' && isNaN(value); };
typeof 只能判斷基本類型,對于引用類型的到的值都是object
typeof []; // 'object' typeof {}; // 'object' typeof c; // 'object'
instanceof
可以用來檢測引用類型,其原理是檢測 constructor.prototype
是否存在于參數(shù) object 的原型鏈上
{} instanceof Object // true [] instanceof Array // true /reg/ instanceof RegExp // true
instanceof 存在的一個問題是不夠準確,原型鏈上存在的都會返回 true
[] instanceof Array // true [] instanceof Object // true 注意這里
使用 instanceof 做類型判斷時,一定要注意順序問題,如果順序錯誤,可能會得不到正確的結果
function type(x) { if (x instanceof Object) { return 'object'; } // Array永遠得不到正確的類型哦 if (x instanceof Array) { return 'array'; } }
instanceof 另一個冷門的問題是存在多個 iframe 時,其判斷可能會返回錯誤的結果,這個問題一般會在多從窗口之間從傳遞值時發(fā)生
[] instanceof window.frames[0].Array // 返回false [] instanceof window.Array // 返回true
對于數(shù)組的判斷,更好的辦法是使用 ECMAScript 5 帶來的新方法Array.isArray
,這個在任何情況下都可以得到可靠的結果
Array.isArray([]); // true Array.isArray(1); // false
另一種常用的判斷類型方式是使用,獲取內(nèi)部類型的方法,借助Object.prototype.toString
可以獲取內(nèi)部類型的字符串結果
const toString = Object.prototype.toString; toString.call({}); // [object Object] toString.call(null); // [object Null] toString.call(/reg/); // [object RegExp]
需要注意的是,在 ECMAScript 5 之前,undefined 和 null 并不能返回正確的值,如果有兼容性需求,需要注意這個問題
ECMAScript 2015 引入了Symbol.toStringTag
可以修改內(nèi)部類型的值,這會影響toString
的返回值,但是需要注意兼容性問題
const toString = Object.prototype.toString; const obj = {}; toString.call(obj); // '[object Object]' obj[Symbol.toStringTag] = 'MyObject'; // 修改內(nèi)部類型 toString.call(obj); // '[object MyObject]'
總結
至此,本文介紹了在JavaScript中判斷變量類型的各種方法,可以看到在正確的場景使用正確的方式并不容易,這里推薦大家使用作者維護的type庫,type使用的正是本文介紹的知識,其提供了開箱即用的判斷函數(shù),經(jīng)過了很多項目的檢驗,歡迎大家體驗。
到此這篇關于詳解在JavaScript中如何判斷變量類型的文章就介紹到這了,更多相關JavaScript判斷變量類型內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
JavaScript Generator函數(shù)使用分析
生成器Generator是JavaScript ES6引入的特性,它讓我們可以分段執(zhí)行一個函數(shù)。但是在談論生成器(Generator)之前,我們要先了解迭代器Iterator2022-10-10JavaScript實現(xiàn)單擊下拉框選擇直接跳轉頁面的方法
這篇文章主要介紹了JavaScript實現(xiàn)單擊下拉框選擇直接跳轉頁面的方法,涉及javascript控制頁面跳轉的相關技巧,需要的朋友可以參考下2015-07-07Google Map V3 綁定氣泡窗口(infowindow)Dom事件實現(xiàn)代碼
無法在infowindow里面添加的div進行綁定事件處理,官方的API,發(fā)現(xiàn)了google.maps.InfoWindow下面的Events里面有個domready事件2013-04-04