Javascript 由于各種各樣的原因,在判斷一個(gè)變量的數(shù)據(jù)類型方面一直存在著一些問(wèn)題,其中最典型的問(wèn)題恐怕就是 typeof null 會(huì)返回 object 了吧。因此在這里簡(jiǎn)單的總結(jié)一下判斷數(shù)據(jù)類型時(shí)常見(jiàn)的陷阱,以及正確的處理姿勢(shì)。


javascript 數(shù)據(jù)類型

MDN 數(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 的陷阱

MDN 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

MDN 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)完成下列處理。

  1. 創(chuàng)建 String 類型的一個(gè)實(shí)例;

  2. 在實(shí)例上調(diào)用指定的方法;

  3. 銷毀這個(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()

MDN reference

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)算符

MDN reference

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/

作者 Githubhttps://github.com/pspgbhu

歡迎轉(zhuǎn)載,但請(qǐng)注明出處,謝謝!

http://www.cnblogs.com/pspgbhu/p/7149124.html