JS中如何準確判斷數據類型

在個人第一篇文章裏,介紹過JS各大類型並使用typeof進行輸出查看.也有提到過每一個函數都有一個本身的內部屬性[[class]],這個class指的是js內部分類.這個類的大體包括:數據類型構造函數這兩種。javascript

JavaScript類型介紹 java

咱們講過JS的幾大數據類型,也用typeof查看了幾個簡單的數據類型值。那麼今天咱們再來更寬泛的瞭解一下這方面的知識。請看以下代碼。
var num = 123;
var str = 'aflypig';
var bool = true;
var arr = [1, 2, 3, 4];
var obj = {name:'aflypig', age:21};
var func = function(){ console.log('this is function'); }
var und = undefined;
var nul = null;
var date = new Date();
var reg = /^[a-zA-Z]{5,20}$/;
var error= new Error();

顯然,上次咱們只用typeof查看了幾個經常使用的數據類型,但此次多了一些內置構造函數,還有Array(上次特地沒講Array)類型。那麼步入正題,咱們怎樣才能準確得得到這些(再強調一次,這裏不是變量,JS當中衡量類型的是值,變量是儲存值的容器)數據類型呢?jquery

其實,一共有四種方法,但能徹底準確地識別出它們的只有一種方法,這也是面試過程當中家常便飯的一道題。面試

若是判斷不一樣類型

typeof

typeof num //number
   typeif str //string
   typeof bool //boolean
   typeof arr //object
   typeof obj //object
   typeof func//function
   typeof und //undefined
   typeof nul //object
   typeof date //object
   tyepof reg //object
   tyoeof error //object

解析:typeof能夠識別簡單基本類型值(好比:number,string,boolean),但對於複合類型(Object,Array,Function)卻只能識別Function。segmentfault

undefined和null自己就是JS一直以來的bug,此處typeof `undefined`能夠識別出正確的類型值,但null被歸類到`Object`你們庭中。
        對於此處的 date && reg && error 類型都是實例後的對象,typeof並不會深刻識別他們的`構造函數`(這裏不是數據類型)。顯然typeof並不能處理這種複雜的類型。

總結:typeof能夠看做JS內部已經定義好的各個類型返回其對應的字符串,它不深刻值自己,不進行類型轉換,只針對於當前值返回其對應的類型值。一樣的數據類型經過typeof運算符運算都是同樣的,它沒有原理可言,JS就是這樣定義的,咱們只管記死它。瀏覽器

instanceof

經過上面的typeof判斷,咱們知道它並不能知足一些內置構造函數建立的 僞類型。那麼,咱們這裏來使用 constructor 查看他們的構造函數,從而分辨它們的類型。
num instanceof Number  //false
   str instanceof String   //false
   bool instanceof Boolean   //false
  
        arr instanceof Array  //true
    obj instaneof Object  //true
    func instanceof Function  //true
        und instanceof  Object   //false
        nul instanceof   Object  //false
        date instanceof Date //true
    reg instanceof RegExp //true
    error instanceof Error //true

解析:這裏咱們使用instanceof來複合判斷的是否爲對應類型。首先,咱們先看false項,num str bool 這三個在使用instanceof 時並無包裝封裝對象且instanceof則是根據函數

constructor

num.constructor .name    //Numer
  str.constructor.name  //String
  bool.constructor.name  //Boolean
  arr.constructor.name  //Array
  obj.constructor.name  //Objeact
  func.constructor.name  //Function
  und.constructor.name  // TypeError
  nul.constructor.name  //TypeError
  date.constructor.name //Date
  reg.constructor.name // RegExp
  error.constructor.name //Error
上面除了undefined 和 null 類型錯誤(二者都沒有屬性值)以外, 其餘均可以得到咱們想要的數據類型。但實際真的如此嗎?
// 1⃣️
  var Structure =  function (){ }
  
  var ins = new Structure();
 
  ins.constructor.name  //Structure 
 
 //2⃣️
  
   var Person = function(){}
   var Student = function(){}
   
   Person.prototype = new Student();
   var obj = new Person();
   
   obj.constructor === Student

解析:第一種狀況,對於經過咱們的構造函數生成的實例,不能準確得得到其對應得類型名稱,這一點恐怕就已經遏制了咱們使用這種方式。大數據

第二種狀況,因爲對象的構造函數是`可變的`,`不許確的`,咱們仍是沒法準確的經過constructor得到具體的類型.

總結:經過constructor咱們能夠獲得 instance不能獲得的 str num bool 這些基本類型值,但另外一個問題又浮現出來,constructor的可變性,因爲它的不肯定性,咱們在不少狀況下都沒法判斷出正確的數據類型,因此使用constructor這個方法也差很少廢了....this

[[Class]]

解析:此[[class]]指的是隱藏在javascript內部的分類屬性,它不可讀,不可枚舉,不可修改,不可配置。(兩邊出現__下劃線__的屬性都屬於部分瀏覽器支持的屬性。[[]]兩個中括號括起來的屬性屬於JavaScript內部屬性。),我記得上一章說過,JavaScript中一切皆爲對象的理念,咱們能夠強制把它轉換成字符串,使它暴露出內部的[[class]]屬性。prototype

瞭解了以上各類方法,咱們發現它們只能完成部分的類型驗證,有些狀況是可變和不許確的。

Object.prototype.toString.call(num);   //  "[object Number]"
Object.prototype.toString.call(str);   //  "[object String]"
Object.prototype.toString.call(bool);  //  "[object Boolean]"
Object.prototype.toString.call(arr);   //  "[object Array]"
Object.prototype.toString.call(func);  //  "[object Function]"
Object.prototype.toString.call(und);   //  "[object Undefined]"
Object.prototype.toString.call(nul);   //  "[object Null]"
Object.prototype.toString.call(date);  //  "[object Date]"
Object.prototype.toString.call(reg);   //  "[object RegExp]"
Object.prototype.toString.call(error);  //  "[object Error]"
 
arr instanceof Array  //true
    obj instaneof Object  //true
    func instanceof Function  //true
        und instanceof  Object   //false
        nul instanceof   Object  //false
        date instanceof Date //true
    reg instanceof RegExp //true
    error instanceof Error //true

咱們經過 Object 的 toString 方法來查看了當前對象的數據類型,咱們看到使用這種方式能夠完美的查看對應的數據類型,正是咱們想要的,並且每一個對象都有屬於本身的[[class]],咱們能夠理解爲,它是JavaScript根據內置構造函數作出的內部分類。

對於這種常用原生js又難以需求的狀況下,怎麼能少得了jqquery呢?

如下是與jQuery.type()函數相關的jQuery示例代碼:

jQuery.type( undefined ); // "undefined"
jQuery.type( null ); // "null"
 
jQuery.type( true ); // "boolean"
jQuery.type( new Boolean(true) ); // "boolean"
 
jQuery.type( 3 ); // "number"
jQuery.type( new Number(3) ); // "number"
 
jQuery.type( "test" ); // "string"
jQuery.type( new String("test") ); // "string"
 
jQuery.type( function(){} ); // "function"
jQuery.type( new Function() ); // "function"
 
jQuery.type( [] ); // "array"
jQuery.type( new Array() ); // "array"
 
jQuery.type( new Date() ); // "date"
 
jQuery.type( new Error() ); // "error" // jQuery 1.9 新增支持
 
jQuery.type( /test/ ); // "regexp"
jQuery.type( new RegExp("\\d+") ); // "regexp"

jquery內部也是經過咱們剛纔說到的 [[class]]的方式實現的,它返回一個字符串,固定爲小寫字母。
咱們能夠寫行代碼,來簡單的實現jquery中的type方法

function type(o){
    var s  = Object.prototype.toString.call(o);
    return s.slice(s.indexOf(" ")+1,s.length-1).toLowerCase();
}

type(false) //boolean
type({}) //object
type([]) //array
type("") //string
type(/^/) //regexp

但願經過本次粗淺的講解能給你們帶來一點收穫,在知道最終有適合的方式時,應該多去考慮使用另外的方式去實現的手段,由於作這樣能夠擴展本身的知識範圍。就好比上文,若是從後向前列舉,我想有不少人都不會去思考 constructor 和 instance 的不足以及他們的適用範圍吧,
相關文章
相關標籤/搜索