JavaScript類型判斷

JS(ES6)中的基本數據類型:1.數值型(Number):包括整數、浮點數、2.布爾型(Boolean)、3.字符串型(String)、4.數組(Array)、5.空值(Null) 、6.未定義(Undefined),基本數據類型是按值訪問的,由於能夠直接操做保存在變量中的實際值。
引用類型:Object 、Array 、Function 、Data,引用數據類型是保存在堆內存中的對象

1.typeof

var a;
console.log("1:" + typeof a);
var b = null;
console.log("2:" + typeof b);
var c = undefined;
console.log("3:" + typeof c);
var d = new Object;
console.log("4:" + typeof d);
var e = function() {};
console.log("5:" + typeof e);
var f = {};
console.log("6:" + typeof f);
var g = '';
console.log("7:" + typeof g);
var h = [];
console.log("8:" + typeof h);
var i = true;
console.log("9:" + typeof i);
var j = 123;
console.log("10:" + typeof j);
var k = NaN;
console.log("11:" + typeof k);
var l = /^[-+]?\d+$/;
console.log("12:" + typeof l);

打印結果以下
clipboard.pnghtml

總結:typeof對null、undefined、NaN、數組、正則、Object的類型都爲objectjquery


2.constructor

constructor 用於判斷一個變量的原型,constructor 屬性返回對建立此對象的數組函數的引用.
當一個函數 F被定義時,JS引擎會爲F添加 prototype 原型,而後再在 prototype上添加一個 constructor 屬性,並讓其指向 F 的引用,當執行 var f = new F() 時,F 被當成了構造函數,f 是F的實例對象,此時 F 原型上的 constructor 傳遞到了 f 上,所以 f.constructor === F
var F = function(){}
console.log(F.prototype);
var f = new F();
console.log(f.constructor===F) //true

不難看出,F 利用原型對象上的 constructor 引用了自身,當 F 做爲構造函數來建立對象時,原型上的 constructor 就被遺傳到了新建立的對象上, 從原型鏈角度講,構造函數 F 就是新對象的類型。這樣作的意義是,讓新對象在誕生之後,就具備可追溯的數據類型,也就是說對象的constructor屬性指向他的構造函數數組

因此內置對象在內部構建時闊以這樣作出判斷app

圖片描述

函數

  • null 和 undefined 是無效的對象,所以是不會有 constructor 存在的,這兩種類型的數據須要經過其餘方式來判斷
  • constructor屬性並不是必定指向構造函數,他也是能夠修改、變動的(當把F.prototype = {}改寫後,會默認把constructor覆蓋掉)

instanceof

instanceof 運算符用來測試一個對象在其原型鏈中是否存在一個構造函數的 prototype 屬性
及的構造函數有這些基礎類型:String、Number、Boolean、Undefined、Null、Symbol(ES6引入了一種新的原始數據類型Symbol,表示獨一無二的值);
複雜類型:Array,Object;
其餘類型:Function、RegExp、Date。
var obj = new Object()
obj instanceof Object // true

注意左側必須是對象(object),若是不是,直接返回false,列如:測試

var num = 1
num instanceof Number // false

num = new Number(1)
num instanceof Number // true

能夠看出都是num,並且都是1,只是由於第一個不是對象,是基本類型,因此直接返回false,而第二個是封裝成對象,因此true。
這裏要嚴格注意這個問題,有些說法是檢測目標的__proto__與構造函數的prototype相同即返回true,這是不嚴謹的,檢測的必定要是對象才行,如:spa

基礎類型.net

var num = 1
num.__proto__ === Number.prototype // true
num instanceof Number // false

num = new Number(1)
num.__proto__ === Number.prototype // true
num instanceof Number // true
num.__proto__ === (new Number(1)).__proto__ // true

上面例子能夠看出,1與new Number(1)幾乎是同樣的,只是區別在因而否封裝成對象,因此instanceof的結果是不一樣的,string、boolean等,這些基礎類型同樣的。prototype

new String(1) // String {"1"}
String(1) // "1"

new String(1)與String(1)是不一樣的,new是封裝成對象,而沒有new的只是基礎類型轉換,仍是基礎類型
其餘基礎類型同樣的。code

複雜類型,好比數組與對象,甚至函數等,與基礎類型不一樣。

複雜類型

var arr = []
arr instanceof Array // true
arr instanceof Object // true
Array.isArray(arr) // true

複雜類型從字面量是直接生成構造函數的,因此不會像基本類型同樣兩種狀況。
可是上面那個問題,固然,基礎類型也會有這個問題,就是與Object對比。沒辦法,Object在原型鏈的上層,因此都會返回true,以下:

(new Number(1)) instanceof Object // true

因爲從下往上,好比你判斷是Number,那就不必判斷是否是Object了,由於已是Number了……

其餘類型

var reg = new RegExp(//)
reg instanceof RegExp // true
reg instanceof Object // true

var date = new Date()
date instanceof Date // true
date instanceof Object // true

除了Function,都同樣,具體Function以下:

function A() {}
var a = new A()
a instanceof Function // false
a instanceof Object // true
A instanceof Function // true

這裏要注意,function A() {}至關於var A; A = function() {},而後分析:

  1. a是new出來,因此是通過構造,所以已是對象,再也不是函數,因此false
  2. a是通過構造的對象,返回ture沒問題
  3. A是個函數,這沒什麼問題

{}.toString.call(obj)

用法以下

console.log({}.toString.call(1));
console.log({}.toString.call("11"));
console.log({}.toString.call(/123/));
console.log({}.toString.call({}));
console.log({}.toString.call(function() {}));
console.log({}.toString.call([]));
console.log({}.toString.call(true));
console.log({}.toString.call(new Date()));
console.log({}.toString.call(new Error()));
console.log({}.toString.call(null));
console.log({}.toString.call(undefined));
console.log(String(null));
console.log(String(undefined));

返回以下

clipboard.png

注意:必須經過 call 或 apply 來調用,而不能直接調用 toString , 從原型鏈的角度講,全部對象的原型鏈最終都指向了 Object, 按照JS變量查找規則,其餘對象應該也能夠直接訪問到 Object 的 toString方法,而事實上,大部分的對象都實現了自身的 toString 方法,這樣就可能會致使 Object 的 toString 被終止查找,所以要用 call/apply 來強制調用Object 的 toString 方法

jQuery中的方法$.type(),就是用到了toString

type: function( obj ) {
    if ( obj == null ) {
        return obj + "";
    }
    // Support: Android<4.0, iOS<6 (functionish RegExp)
    return typeof obj === "object" || typeof obj === "function" ?
        class2type[ toString.call(obj) ] || "object" :
        typeof obj;
},

分析源代碼:

typeof obj === "object" || typeof obj === "function" ? class2type[ toString.call(obj) ]

經過判斷傳入類型,若是是object或者function類型就直接返回class2type 中鍵值是對的結果,若是不是,那麼必定就是基本類型, 經過 typeof 就能夠

class2type[ toString.call(obj) ] || "object"

這是爲了防止一些未知狀況的,若是未取到,就返回object,保證了程序可用性

參考文章:
JS類型判斷,typeof/constructor/instanceof的區別
js中的constructor和prototype
JS類型判斷
jquery源碼
揭開js之constructor屬性的神祕面紗

相關文章
相關標籤/搜索