當前位置:
首頁 > 知識 > Javascript 判斷變數類型的陷阱 與 正確的處理方式

Javascript 判斷變數類型的陷阱 與 正確的處理方式

Javascript 由於各種各樣的原因,在判斷一個變數的數據類型方面一直存在著一些問題,其中最典型的問題恐怕就是 typeof null會返回object了吧。因此在這裡簡單的總結一下判斷數據類型時常見的陷阱,以及正確的處理姿勢。

javascript 數據類型數據類型

這裡先談一下 javascript 這門語言的數據類型。javascript 中有七種數據類型,其中有六種簡單數據類型,一種複雜數據類型。

六種簡單數據類型
  • String
  • Number
  • Boolean
  • Null
  • Undefined
  • Symbol (ECMAScript 6 新定義)

複雜數據類型

Object是唯一的複雜數據類型。Object Array Function這些引用類型值最終都可以歸結為Object複雜數據類型。

各種陷阱typeof 的陷阱

typeof是用來檢測變數數據類型的操作符,對一個值使用typeof操作符可能會返回下列某個字元串

  • "undefined" --- 如果這個值未定義
  • "string" --- 如果這個值是字元串
  • "boolean" --- 如果這個值是布爾類型值
  • "number" --- 如果這個值是數值
  • "object" --- 如果這個值是對象或者 null
  • "function" --- 如果這個值是函數

1. Object 對象檢測的陷阱

function isObj(obj) {
if (typeof obj === "object") {
return "It is object";
}
return "It is not object";
}

這個函數的本意是想檢測傳入的參數是否是 Object 對象。但是這個函數其實是非常不安全的。

比如

var a = [1, 2, 3];
isObj(a); // "It is object"

var b = null;
isObj(b); // "It is object"

這樣明顯是不對的,因為 typeof typeof null都是是會返回"object"的。

2. Array 對象檢測的陷阱

typeof // "object"

上面說到了對一個數組使用 typeof 操作符也是會返回 "object",因此 typeof 並不能判斷數組對象的類型

instanceof 的陷阱 與 基本包裝類型1. instanceof

instanceof 運算符用來測試一個對象在其原型鏈中是否存在一個構造函數的 prototype 屬性。

2. 基本包裝類

《Javascript》高級程序設計 第五章第六節 基本包裝類型

javascript 為了方便操作基本類型值,ECMAscript 提供了3個特殊的引用類型:Boolean、Number 和 String。 每當讀取一個基本類型值的時候,後台就會創建一個對應的基本包裝類型的對象,從而讓我們能夠調用一些方法來操作這些數據。

var s1 = "some text";
var s2 = s1.substring(2);

上面的代碼中,先創建了一個字元串保存在了變數 s1,字元串當然是基本類型值。但是在下一行中我們又調用了 s1 的方法。我們知道基本類型值不是對象,理論上它不應該擁有方法(但它們確實有方法)。其實,為了讓我們實現這種直觀的操作,後台已經幫助我們完成了一系列的操作。當我們在第二行代碼中訪問 s1 變數時,訪問過程處於讀取模式,而在讀取模式中訪問字元串時,後台都會自動完成下列處理。

  1. 創建 String 類型的一個實例;
  2. 在實例上調用指定的方法;
  3. 銷毀這個實例。

可以將以上三個步驟想像成是執行了下列代碼

var s1 = new String("some text");
var s2 = s1.substring(2);
s1 = null;

3. instanceof 判斷基本類型值的陷阱

上面提到基本包裝類,就是為了說明 instanceof 這個陷阱

var str = "text";
str instanceof String; // false

本來我也是想當然的認為 str instanceof String會使 str 變數處於讀取模式,自動建立基本包裝類。但是根據上述代碼所體現表象來看,instanceof 運算符是直接訪問的變數的原始值。

因此 instanceof 並不能用來判斷五種基本類型值

4. instanceof 判斷 Object類型的陷阱

這裡先說一下,用 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 這個數組實例的原型鏈上。

一個高效但危險的變數類型判斷方法用對象的 constructor 來判斷對象類型

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 來判斷變數類型會埋下一顆非常危險的地雷,我個人非常不推薦使用。

正確判斷變數類型的姿勢一個萬金油方法 Object.prototype.toString.call

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]"

String Boolean Number Undefined 四種基本類型的判斷

除了 Null之外的這四種基本類型值,都可以用typeof操作符很好的進行判斷處理。

typeof "abc" // "string"

typeof false // "boolean"

typeof 123 // "number"

typeof undefined // "undefined"

Null 類型的判斷

除了 Object.prototype.toString.call(null)之外,目前最好的方法就是用variable === null全等來判斷了。

var a = null;

if (a === null) {
console.log("a is null");
}

// a is null

檢測變數是否是一個 Array 數組

typeof 會返回object因此明顯是不能夠用 typeof 操作符進行數組類型判斷的。目前常用的方法有以下幾種

1. Object.prototype.toString.call

萬金油方法是一種。

2. ECMAscript5 新增 Array.isArray

Array.isArray([]); // true

3. instanceof 運算符

因此可以檢測一個對象的原型鏈中是否存在 Array 構造函數的 prototype 屬性來判斷是不是數組。

instanceof Array // true

檢測變數是否是一個 Object 對象

typeof 和 instanceof 都不能安全的判斷變數是否是 Object 對象。

目前判斷變數是否是對象的最安全的方法就只有 Object.prototype.toString.call了。

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 科技優家 的精彩文章:

Asp.net MVC-3-執行過程
Vue.js 基本功能了解
Java 逆變與協變的名詞說明
Jenkins的安裝配置
webpack的Hot Module Replacement運行機制

TAG:科技優家 |

您可能感興趣

python基礎之變數類型number(math模塊)
TypeScript基礎之高級類型的可辨識聯合(Discriminated Unions)
類型轉換運算符 運算符重載 operator new operator delete
Hibernate 映射枚舉Enum 類型的屬性
「Good idea/solution」 類型作文審題
「Python」Chapter1 變數和簡單數據類型
Redis 數據類型
solidity之地址類型
scala學習-泛型、界定、形變、this.type、複合類型、抽象類型
Adobe Reader類型混淆導致代碼執行漏洞分析
python中list,array,mat,tuple大小及類型
Google出品的Python代碼靜態類型分析器:Pytype
Summary 數據類型詳解
Chrome 66 新特性:CSS 類型對象模型,非同步剪貼板 API,AudioWorklet,等
opencv Mat類型和BYTE*指針類型互轉
Pyright:微軟提供的Python靜態類型檢查器
SM、jyp、yg、cube、ymc等公司類型——其中big hit最霸氣
Redis數據類型詳解
python基礎數據類型
Kotlin 基本數據類型