類型判斷(上)

前言

類型判斷在 web 開發中有很是普遍的應用,簡單的有判斷數字仍是字符串,進階一點的有判斷數組仍是對象,再進階一點的有判斷日期、正則、錯誤類型,再再進階一點還有好比判斷 plainObject、空對象、Window 對象等等。jquery

以上都會講,今天是上半場。git

typeof

咱們最最經常使用的莫過於 typeof,注意,儘管咱們會看到諸如:github

console.log(typeof('yayu')) // string

的寫法,可是 typeof 但是一個正宗的運算符,就跟加減乘除同樣!這就能解釋爲何下面這種寫法也是可行的:web

console.log(typeof 'yayu') // string

引用《JavaScript權威指南》中對 typeof 的介紹:數組

typeof 是一元操做符,放在其單個操做數的前面,操做數能夠是任意類型。返回值爲表示操做數類型的一個字符串。函數

那咱們都知道,在 ES6 前,JavaScript 共六種數據類型,分別是:this

Undefined、Null、Boolean、Number、String、Objectes5

然而當咱們使用 typeof 對這些數據類型的值進行操做的時候,返回的結果卻不是一一對應,分別是:spa

undefined、object、boolean、number、string、objectprototype

注意以上都是小寫的字符串。Null 和 Object 類型都返回了 object 字符串。

儘管不能一一對應,可是 typeof 卻能檢測出函數類型:

function a() {} console.log(typeof a); // function

因此 typeof 能檢測出六種類型的值,可是,除此以外 Object 下還有不少細分的類型吶,如 Array、Function、Date、RegExp、Error 等。

若是用 typeof 去檢測這些類型,舉個例子:

var date = new Date(); var error = new Error(); console.log(typeof date); // object console.log(typeof error); // object

返回的都是 object 吶,這可怎麼區分~ 因此有沒有更好的方法呢?

Obejct.prototype.toString

是的,固然有!這就是 Object.prototype.toString!

那 Object.protototype.toString 到底是一個什麼樣的方法呢?

爲了更加細緻的講解這個函數,讓我先獻上 ES5 規範地址:https://es5.github.io/#x15.2.4.2

在第 15.2.4.2 節講的就是 Object.prototype.toString(),爲了避免誤導你們,我先奉上英文版:

When the toString method is called, the following steps are taken:

  1. If the this value is undefined, return "[object Undefined]".
  2. If the this value is null, return "[object Null]".
  3. Let O be the result of calling ToObject passing the this value as the argument.
  4. Let class be the value of the [[Class]] internal property of O.
  5. Return the String value that is the result of concatenating the three Strings "[object ", class, and "]".

凡是規範上加粗或者斜體的,在這裏我也加粗或者斜體了,就是要讓你們感覺原汁原味的規範!

若是沒有看懂,就不妨看看我理解的:

當 toString 方法被調用的時候,下面的步驟會被執行:

  1. 若是 this 值是 undefined,就返回 [object Undefined]
  2. 若是 this 的值是 null,就返回 [object Null]
  3. 讓 O 成爲 ToObject(this) 的結果
  4. 讓 class 成爲 O 的內部屬性 [[Class]] 的值
  5. 最後返回由 "[object " 和 class 和 "]" 三個部分組成的字符串

經過規範,咱們至少知道了調用 Object.prototype.toString 會返回一個由 "[object " 和 class 和 "]" 組成的字符串,而 class 是要判斷的對象的內部屬性。

讓咱們寫個 demo:

console.log(Object.prototype.toString.call(undefined)) // [object Undefined] console.log(Object.prototype.toString.call(null)) // [object Null] var date = new Date(); console.log(Object.prototype.toString.call(date)) // [object Date]

由此咱們能夠看到這個 class 值就是識別對象類型的關鍵!

正是由於這種特性,咱們能夠用 Object.prototype.toString 方法識別出更多類型!

那到底能識別多少種類型呢?

至少 12 種!

你咋知道的?

我數的!

……

讓咱們看個 demo:

// 如下是11種: var number = 1; // [object Number] var string = '123'; // [object String] var boolean = true; // [object Boolean] var und = undefined; // [object Undefined] var nul = null; // [object Null] var obj = {a: 1} // [object Object] var array = [1, 2, 3]; // [object Array] var date = new Date(); // [object Date] var error = new Error(); // [object Error] var reg = /a/g; // [object RegExp] var func = function a(){}; // [object Function] function checkType() { for (var i = 0; i < arguments.length; i++) { console.log(Object.prototype.toString.call(arguments[i])) } } checkType(number, string, boolean, und, nul, obj, array, date, error, reg, func) 

除了以上 11 種以外,還有:

console.log(Object.prototype.toString.call(Math)); // [object Math] console.log(Object.prototype.toString.call(JSON)); // [object JSON]

除了以上 13 種以外,還有:

function a() { console.log(Object.prototype.toString.call(arguments)); // [object Arguments] } a();

因此咱們能夠識別至少 14 種類型,固然咱們也能夠算出來,[[class]] 屬性至少有 12 個。

type API

既然有了 Object.prototype.toString 這個神器!那就讓咱們寫個 type 函數幫助咱們之後識別各類類型的值吧!

個人設想:

寫一個 type 函數能檢測各類類型的值,若是是基本類型,就使用 typeof,引用類型就使用 toString。此外鑑於 typeof 的結果是小寫,我也但願全部的結果都是小寫。

考慮到實際狀況下並不會檢測 Math 和 JSON,因此去掉這兩個類型的檢測。

咱們來寫一版代碼:

// 初版 var class2type = {}; // 生成class2type映射 "Boolean Number String Function Array Date RegExp Object Error Null Undefined".split(" ").map(function(item, index) { class2type["[object " + item + "]"] = item.toLowerCase(); }) function type(obj) { return typeof obj === "object" || typeof obj === "function" ? class2type[Object.prototype.toString.call(obj)] || "object" : typeof obj; }

嗯,看起來很完美的樣子~~ 可是注意,在 IE6 中,null 和 undefined 會被 Object.prototype.toString 識別成 [object Object]!

我去,居然還有這個兼容性!有什麼簡單的方法能夠解決嗎?那咱們再改寫一版,絕對讓你驚豔!

// 第二版 var class2type = {}; // 生成class2type映射 "Boolean Number String Function Array Date RegExp Object Error".split(" ").map(function(item, index) { class2type["[object " + item + "]"] = item.toLowerCase(); }) function type(obj) { // 一舉兩得 if (obj == null) { return obj + ""; } return typeof obj === "object" || typeof obj === "function" ? class2type[Object.prototype.toString.call(obj)] || "object" : typeof obj; }

isFunction

有了 type 函數後,咱們能夠對經常使用的判斷直接封裝,好比 isFunction:

function isFunction(obj) { return type(obj) === "function"; }

數組

jQuery 判斷數組類型,舊版本是經過判斷 Array.isArray 方法是否存在,若是存在就使用該方法,不存在就使用 type 函數。

var isArray = Array.isArray || function( obj ) { return type(obj) === "array"; }

可是在 jQuery v3.0 中已經徹底採用了 Array.isArray。

結語

到此,類型判斷的上篇就結束了,咱們已經能夠判斷日期、正則、錯誤類型啦,可是還有更復雜的判斷好比 plainObject、空對象、Window對象、類數組對象等,路漫漫其修遠兮,吾將上下而求索。

哦, 對了,這個 type 函數抄的 jQuery,點擊查看 type 源碼

相關文章
相關標籤/搜索