JS判斷數據類型


在JS中,數據類型包括

  • 基礎類型(String、Number、Boolean、Undefined、Null )
  • 引用類型(除 Object 外,還包括 Function 、Array、RegExp、Date 等)

1. typeof

簡記為
a.對于基本類型,除null外,其他返回值都有效
b.對于引用類型,除function返回值有效為function,其他都返回object
c.null返回值為"object"

2. instanceof

instanceof檢測對象在其原型鏈上是否能找到構造函數的prototype屬性

我們用一段偽代碼來表示一下instanceof

instanceof(object,constructor){
  if(object._proto_===constructor.prototype){
    return true
  }else{
    return false;
  }
}

來舉些例子


{} instanceof Object;//true
new Date() instanceof Date;//true
 
function Person(){};
new Person() instanceof Person;

[] instanceof Array; //true
[] instanceof Object; //true

我們發現,雖然 instanceof 能夠判斷出 [ ] 是Array的實例,但它認為 [ ] 也是Object的實例,為什么呢?

我們來分析一下 [ ]、Array、Object 三者之間的關系:

從 instanceof 能夠判斷出 [ ].proto 指向 Array.prototype,而 Array.prototype.proto 又指向了Object.prototype,最終 Object.prototype.proto 指向了null,標志著原型鏈的結束。因此,[]、Array、Object 就在內部形成了一條原型鏈


從原型鏈可以看出,[] 的 proto 直接指向Array.prototype,間接指向 Object.prototype,所以按照 instanceof 的判斷規則,[] 就是Object的實例

3. constructor

當一個函數 F被定義時,JS引擎會為F添加 prototype 原型,然后再在 prototype上添加一個 constructor 屬性,并讓其指向 F 的引用。如下所示:



當執行 var f = new F() 時,F 被當成了構造函數,f 是F的實例對象,此時 F 原型上的 constructor 傳遞到了 f 上,因此 f.constructor == F



可以看出,F 利用原型對象上的 constructor 引用了自身,當 F 作為構造函數來創建對象時,原型上的 constructor 就被遺傳到了新創建的對象上, 從原型鏈角度講,構造函數 F 就是新對象的類型

細節問題

  • null 和 undefined 是無效的對象,因此是不會有 constructor 存在的,這兩種類型的數據需要通過其他方式來判斷。
  • 函數的 constructor 是不穩定的,這個主要體現在自定義對象上,當開發者重寫 prototype 后,原有的 constructor 引用會丟失,constructor 會默認為 Object

為什么變成了 Object?
因為 prototype 被重新賦值的是一個 { }, { } 是 new Object() 的字面量,因此 new Object() 會將 Object 原型上的 constructor 傳遞給 { },也就是 Object 本身。
因此,為了規范開發,在重寫對象原型時一般都需要重新給 constructor 賦值,以保證對象實例的類型不被篡改。

4. toString

toString 是 Object 原型對象上的方法,使用 call 來調用該方法會返回調用者的類型字符串,格式為 [object,xxx],xxx 是調用者的數據類型,包括:String、Number、Boolean、Undefined、Null、Function、Date、Array、RegExp、Error、HTMLDocument等, 基本上,所有的數據類型都可以通過這個方法獲取到。

Object.prototype.toString.call('') ;   // [object String]
Object.prototype.toString.call(1) ;    // [object Number]
Object.prototype.toString.call(true) ; // [object Boolean]
Object.prototype.toString.call(Symbol()); //[object Symbol]
Object.prototype.toString.call(undefined) ; // [object Undefined]
Object.prototype.toString.call(null) ; // [object Null]
Object.prototype.toString.call(new Function()) ; // [object Function]
Object.prototype.toString.call(new Date()) ; // [object Date]
Object.prototype.toString.call([]) ; // [object Array]
Object.prototype.toString.call(new RegExp()) ; // [object RegExp]
Object.prototype.toString.call(new Error()) ; // [object Error]
Object.prototype.toString.call(document) ; // [object HTMLDocument]
Object.prototype.toString.call(window) ; //[object global] window是全局對象 global 的引用

為什么所有引用類型都會繼承toString方法

因為引用類型繼承Object,這個繼承也是通過原型鏈實現的。那就說明引用類型的原型包含一個內部指針指向Object.prototype

為什么要通過 call 或 apply 來調用

按照JS原型搜索機制,其他對象應該也可以直接訪問到 Object 的 toString方法,而事實上,大部分的對象都實現了自身的 toString 方法,這樣就可能會導致 Object 的 toString 被終止查找,因此要用 call/apply 來強制調用Object 的 toString

每天都努力一點點
謝謝你看完


最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容