Javascript 由于各種各樣的原因,在判斷一個(gè)變量的數(shù)據(jù)類型方面一直存在著一些問(wèn)題,其中最典型的問(wèn)題恐怕就是 typeof null
會(huì)返回 object
了吧。因此在這里簡(jiǎn)單的總結(jié)一下判斷數(shù)據(jù)類型時(shí)常見(jiàn)的陷阱,以及正確的處理姿勢(shì)。
javascript 數(shù)據(jù)類型
數(shù)據(jù)類型
這里先談一下 javascript 這門語(yǔ)言的數(shù)據(jù)類型。javascript 中有七種數(shù)據(jù)類型,其中有六種簡(jiǎn)單數(shù)據(jù)類型,一種復(fù)雜數(shù)據(jù)類型。
六種簡(jiǎn)單數(shù)據(jù)類型
String
Number
Boolean
Null
Undefined
Symbol (ECMAScript 6 新定義)
復(fù)雜數(shù)據(jù)類型
Object
是唯一的復(fù)雜數(shù)據(jù)類型。 Object Array Function
這些引用類型值最終都可以歸結(jié)為 Object
復(fù)雜數(shù)據(jù)類型。
各種陷阱
typeof 的陷阱
typeof
是用來(lái)檢測(cè)變量數(shù)據(jù)類型的操作符,對(duì)一個(gè)值使用 typeof
操作符可能會(huì)返回下列某個(gè)字符串
"undefined" --- 如果這個(gè)值未定義
"string" --- 如果這個(gè)值是字符串
"boolean" --- 如果這個(gè)值是布爾類型值
"number" --- 如果這個(gè)值是數(shù)值
"object" --- 如果這個(gè)值是對(duì)象或者 null
"function" --- 如果這個(gè)值是函數(shù)
1. Object 對(duì)象檢測(cè)的陷阱
function isObj(obj) { if (typeof obj === 'object') { return 'It is object'; } return 'It is not object';}
這個(gè)函數(shù)的本意是想檢測(cè)傳入的參數(shù)是否是 Object 對(duì)象。但是這個(gè)函數(shù)其實(shí)是非常不安全的。
比如
var a = [1, 2, 3]; isObj(a); // 'It is object'var b = null; isObj(b); // 'It is object'
這樣明顯是不對(duì)的,因?yàn)?nbsp;typeof []
和 typeof null
都是是會(huì)返回 'object'
的。
2. Array 對(duì)象檢測(cè)的陷阱
typeof [] // 'object'
上面說(shuō)到了對(duì)一個(gè)數(shù)組使用 typeof 操作符也是會(huì)返回 'object'
,因此 typeof 并不能判斷數(shù)組對(duì)象的類型
instanceof 的陷阱 與 基本包裝類型
1. instanceof
instanceof 運(yùn)算符用來(lái)測(cè)試一個(gè)對(duì)象在其原型鏈中是否存在一個(gè)構(gòu)造函數(shù)的 prototype 屬性。
2. 基本包裝類
《Javascript》高級(jí)程序設(shè)計(jì) 第五章第六節(jié) 基本包裝類型
javascript 為了方便操作基本類型值,ECMAscript 提供了3個(gè)特殊的引用類型:Boolean、Number 和 String。
每當(dāng)讀取一個(gè)基本類型值的時(shí)候,后臺(tái)就會(huì)創(chuàng)建一個(gè)對(duì)應(yīng)的基本包裝類型的對(duì)象,從而讓我們能夠調(diào)用一些方法來(lái)操作這些數(shù)據(jù)。
var s1 = "some text";var s2 = s1.substring(2);
上面的代碼中,先創(chuàng)建了一個(gè)字符串保存在了變量 s1,字符串當(dāng)然是基本類型值。但是在下一行中我們又調(diào)用了 s1 的方法。我們知道基本類型值不是對(duì)象,理論上它不應(yīng)該擁有方法(但它們確實(shí)有方法)。其實(shí),為了讓我們實(shí)現(xiàn)這種直觀的操作,后臺(tái)已經(jīng)幫助我們完成了一系列的操作。當(dāng)我們?cè)诘诙写a中訪問(wèn) s1 變量時(shí),訪問(wèn)過(guò)程處于讀取模式,而在讀取模式中訪問(wèn)字符串時(shí),后臺(tái)都會(huì)自動(dòng)完成下列處理。
創(chuàng)建 String 類型的一個(gè)實(shí)例;
在實(shí)例上調(diào)用指定的方法;
銷毀這個(gè)實(shí)例。
可以將以上三個(gè)步驟想像成是執(zhí)行了下列代碼
var s1 = new String("some text");var s2 = s1.substring(2);s1 = null;
3. instanceof 判斷基本類型值的陷阱
上面提到基本包裝類,就是為了說(shuō)明 instanceof 這個(gè)陷阱
var str = 'text';str instanceof String; // false
本來(lái)我也是想當(dāng)然的認(rèn)為 str instanceof String
會(huì)使 str 變量處于讀取模式,自動(dòng)建立基本包裝類。但是根據(jù)上述代碼所體現(xiàn)表象來(lái)看,instanceof 運(yùn)算符是直接訪問(wèn)的變量的原始值。
因此 instanceof 并不能用來(lái)判斷五種基本類型值
4. instanceof 判斷 Object類型的陷阱
這里先說(shuō)一下,用 instanceof 判斷 Array 類型基本上是非常ok的
var arr = [1, 2, 3];arr instanceof Array; // true
但是 instanceof 卻不能安全的判斷 Object 類型,因?yàn)?Array 構(gòu)造函數(shù)是繼承自 Object 對(duì)象的,因此在 arr 變量上是可以訪問(wèn)到 Object 的 prototype 屬性的。如下例所示:
var arr = [1, 2, 3];arr instanceof Object; // true// 會(huì)返回 true ,是因?yàn)?nbsp;Object 構(gòu)造函數(shù)的 prototype 屬性存在與 arr 這個(gè)數(shù)組實(shí)例的原型鏈上。
一個(gè)高效但危險(xiǎn)的變量類型判斷方法
用對(duì)象的 constructor 來(lái)判斷對(duì)象類型
stack overflow 上有人做了實(shí)驗(yàn),說(shuō)是目前運(yùn)算最快的判斷變量類型的方式。
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' }}
上面是一個(gè)判斷變量類型的方法,工作的非常高效完美。但是用 constructor 判斷變量類型有一個(gè)致命的缺陷,就是當(dāng)檢測(cè) null 或者 undefined 類型的 constructor 屬性時(shí),js會(huì)報(bào)錯(cuò)!
也就是說(shuō)下面代碼會(huì)報(bào)錯(cuò)!
cstor(null); // 若傳入 null 或者 undefined 作為參數(shù)時(shí) // cstor 函數(shù)第一行就會(huì)報(bào)錯(cuò),因?yàn)?nbsp;null 和 undefined 根本就沒(méi)有 constructor 屬性
因此我們?cè)诶米兞康?constructor 屬性來(lái)判斷變量類型時(shí),必須要先保證變量有 不會(huì)是 null 或者 undefined。
改造以上函數(shù)如下:
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' }}
所以說(shuō)使用 constructor 來(lái)判斷對(duì)象類型時(shí)要無(wú)時(shí)無(wú)刻不伴隨著排除 null 和 undefined 的干擾,否則就會(huì)產(chǎn)生致命的問(wèn)題,因此本人并不推薦。
正確判斷變量類型的姿勢(shì)
一個(gè)萬(wàn)金油方法 Object.prototype.toString.call()
Object.prototype.toString.call(variable)
用這個(gè)方法來(lái)判斷變量類型目前是最可靠的了,它總能返回正確的值。
該方法返回 "[object type]"
, 其中type是對(duì)象類型。
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]"
String Boolean Number Undefined 四種基本類型的判斷
除了 Null
之外的這四種基本類型值,都可以用 typeof
操作符很好的進(jìn)行判斷處理。
typeof 'abc' // "string"typeof false // "boolean"typeof 123 // "number"typeof undefined // "undefined"
Null 類型的判斷
除了 Object.prototype.toString.call(null)
之外,目前最好的方法就是用 variable === null
全等來(lái)判斷了。
var a = null;if (a === null) { console.log('a is null'); }// a is null
檢測(cè)變量是否是一個(gè) Array 數(shù)組
typeof []
會(huì)返回 object
因此明顯是不能夠用 typeof 操作符進(jìn)行數(shù)組類型判斷的。目前常用的方法有以下幾種
1. Object.prototype.toString.call()
萬(wàn)金油方法是一種。
2. ECMAscript5 新增 Array.isArray()
Array.isArray([]); // true
3. instanceof 運(yùn)算符
instanceof 運(yùn)算符用來(lái)測(cè)試一個(gè)對(duì)象在其原型鏈中是否存在一個(gè)構(gòu)造函數(shù)的 prototype 屬性。
因此可以檢測(cè)一個(gè)對(duì)象的原型鏈中是否存在 Array 構(gòu)造函數(shù)的 prototype 屬性來(lái)判斷是不是數(shù)組。
[] instanceof Array // true
檢測(cè)變量是否是一個(gè) Object 對(duì)象
typeof 和 instanceof 都不能安全的判斷變量是否是 Object 對(duì)象。
目前判斷變量是否是對(duì)象的最安全的方法就只有 Object.prototype.toString.call()
了。
作者博客:pspgbhu http://www.cnblogs.com/pspgbhu/
作者 Github:https://github.com/pspgbhu
歡迎轉(zhuǎn)載,但請(qǐng)注明出處,謝謝!
http://www.cnblogs.com/pspgbhu/p/7149124.html