Javascript 因爲各類各樣的緣由,在判斷一個變量的數據類型方面一直存在着一些問題,其中最典型的問題恐怕就是 typeof null
會返回 object
了吧。所以在這裏簡單的總結一下判斷數據類型時常見的陷阱,以及正確的處理姿式。javascript
MDN 數據類型java
這裏先談一下 javascript 這門語言的數據類型。javascript 中有七種數據類型,其中有六種簡單數據類型,一種複雜數據類型。git
Object
是惟一的複雜數據類型。 Object Array Function
這些引用類型值最終均可以歸結爲 Object
複雜數據類型。github
typeof
是用來檢測變量數據類型的操做符,對一個值使用 typeof
操做符可能會返回下列某個字符串安全
function isObj(obj) { if (typeof obj === 'object') { return 'It is object'; } return 'It is not object'; }
這個函數的本意是想檢測傳入的參數是不是 Object 對象。可是這個函數實際上是很是不安全的。ecmascript
好比函數
var a = [1, 2, 3]; isObj(a); // 'It is object' var b = null; isObj(b); // 'It is object'
這樣明顯是不對的,由於 typeof []
和 typeof null
都是是會返回 'object'
的。測試
typeof [] // 'object'
上面說到了對一個數組使用 typeof 操做符也是會返回 'object'
,所以 typeof 並不能判斷數組對象的類型prototype
instanceof 運算符用來測試一個對象在其原型鏈中是否存在一個構造函數的 prototype 屬性。
《Javascript》高級程序設計 第五章第六節 基本包裝類型
javascript 爲了方便操做基本類型值,ECMAscript 提供了3個特殊的引用類型:Boolean、Number 和 String。
每當讀取一個基本類型值的時候,後臺就會建立一個對應的基本包裝類型的對象,從而讓咱們可以調用一些方法來操做這些數據。
var s1 = "some text"; var s2 = s1.substring(2);
上面的代碼中,先建立了一個字符串保存在了變量 s1,字符串固然是基本類型值。可是在下一行中咱們又調用了 s1 的方法。咱們知道基本類型值不是對象,理論上它不該該擁有方法(但它們確實有方法)。其實,爲了讓咱們實現這種直觀的操做,後臺已經幫助咱們完成了一系列的操做。當咱們在第二行代碼中訪問 s1 變量時,訪問過程處於讀取模式,而在讀取模式中訪問字符串時,後臺都會自動完成下列處理。
能夠將以上三個步驟想像成是執行了下列代碼
var s1 = new String("some text"); var s2 = s1.substring(2); s1 = null;
上面提到基本包裝類,就是爲了說明 instanceof 這個陷阱
var str = 'text'; str instanceof String; // false
原本我也是想固然的認爲 str instanceof String
會使 str 變量處於讀取模式,自動創建基本包裝類。可是根據上述代碼所體現表象來看,instanceof 運算符是直接訪問的變量的原始值。
所以 instanceof 並不能用來判斷五種基本類型值
這裏先說一下,用 instanceof 判斷 Array 類型基本上是很是ok的
var arr = [1, 2, 3]; arr instanceof Array; // true
可是 instanceof 卻不能安全的判斷 Object 類型,由於 Array 構造函數是繼承自 Object 對象的,所以在 arr 變量上是能夠訪問到 Object 的 prototype 屬性的。以下例所示:
var arr = [1, 2, 3]; arr instanceof Object; // true // 會返回 true ,是由於 Object 構造函數的 prototype 屬性存在與 arr 這個數組實例的原型鏈上。
stack overflow 上有人作了實驗,說是目前運算最快的判斷變量類型的方式。
function cstor(variable) { var cst = variable.constructor; switch (cst) { case Number: return 'Number' case String: return 'String' case Boolean: return 'Boolean' case Array: return 'Array' case Object: return 'Object' } }
上面是一個判斷變量類型的方法,工做的很是高效完美。可是用 constructor 判斷變量類型有一個致命的缺陷,就是當檢測 null 或者 undefined 類型的 constructor 屬性時,js會報錯!
也就是說下面代碼會報錯!
cstor(null); // 若傳入 null 或者 undefined 做爲參數時 // cstor 函數第一行就會報錯,由於 null 和 undefined 根本就沒有 constructor 屬性
所以咱們在利用變量的 constructor 屬性來判斷變量類型時,必需要先保證變量有 不會是 null 或者 undefined。
改造以上函數以下:
function cstor(variable) { if (variable === null || variable === undefined) { return 'Null or Undefined'; } var cst = variable.constructor; switch (cst) { case Number: return 'Number' case String: return 'String' case Boolean: return 'Boolean' case Array: return 'Array' case Object: return 'Object' } }
因此說使用 constructor 來判斷對象類型時要無時無刻不伴隨着排除 null 和 undefined 的干擾,不然就會產生致命的問題,所以本人並不推薦。
Object.prototype.toString.call(variable)
用這個方法來判斷變量類型目前是最可靠的了,它總能返回正確的值。
該方法返回 "[object type]"
, 其中type是對象類型。
Object.prototype.toString.call(null); // "[object Null]" Object.prototype.toString.call([]); // "[object Array]" Object.prototype.toString.call({}); // "[object Object]" Object.prototype.toString.call(123); // "[object Number]" Object.prototype.toString.call('123'); // "[object String]" Object.prototype.toString.call(false); // "[object Boolean]" Object.prototype.toString.call(undefined); // "[object Undefined]"
除了 Null
以外的這四種基本類型值,均可以用 typeof
操做符很好的進行判斷處理。
typeof 'abc' // "string" typeof false // "boolean" typeof 123 // "number" typeof undefined // "undefined"
除了 Object.prototype.toString.call(null)
以外,目前最好的方法就是用 variable === null
全等來判斷了。
var a = null; if (a === null) { console.log('a is null'); } // a is null
typeof []
會返回 object
所以明顯是不可以用 typeof 操做符進行數組類型判斷的。目前經常使用的方法有如下幾種
萬金油方法是一種。
Array.isArray([]); // true
instanceof 運算符用來測試一個對象在其原型鏈中是否存在一個構造函數的 prototype 屬性。
所以能夠檢測一個對象的原型鏈中是否存在 Array 構造函數的 prototype 屬性來判斷是否是數組。
[] instanceof Array // true
typeof 和 instanceof 都不能安全的判斷變量是不是 Object 對象。
目前判斷變量是不是對象的最安全的方法就只有 Object.prototype.toString.call()
了。
做者博客:pspgbhu http://www.cnblogs.com/pspgbhu/
做者 Github:https://github.com/pspgbhu
歡迎轉載,但請註明出處,謝謝!