JavaScript類型判斷的1010種方式(史上最全)

注:本文首發於個人博客,想得到更好的閱讀體驗,點我移步git

在最新的 ECMAScript規範 中,一共定義了 7 種數據類型,github

  • 基本類型:String、Number、Boolean、Symbol、Undefined、Null
  • 引用類型:Object

基本類型是存儲在 棧(Stack) 中的簡單數據段,引用類型的值是存儲在 堆(Heap) 中的對象。面試

數據類型的值存儲在堆中仍是棧中,取決於值的特性。基本類型佔據的空間固定,存儲在棧中按值訪問,能夠提高變量的查詢速度。引用類型的值大小不固定,不適合存儲在棧中,JavaScript中採起的作法是,將引用類型的值存儲在堆中,同時在棧中存儲值的訪問地址,因此引用類型是 按地址訪問 的。app

var arr = [1, 2, 3] // 引用類型的值其實就是存儲在堆內存中的對象,訪問方式爲按地址訪問,首先找到棧區中值的地址,而後沿着地址找到堆內存中對應的對象。
複製代碼

對於數據類型的判斷,JavaScript 也提供了不少種方法,遺憾的是,不一樣的方法獲得的結果良莠不齊,下面列出了我所知道的全部的類型判斷方法,若是有遺漏,歡迎在評論區補充。函數

typeof

typeof 返回未經計算的操做數的類型的字符串,可能會有一些意料以外的結果:ui

typeof null  === 'object' // true, 從一開始出現 JavaScript 就是這樣的
typeof NaN === 'number' // true, 儘管 NaN 是 Not-A-Number 的縮寫,typeof 仍是會返回 number
typeof [] === 'object' // true, 引用類型除了 function 外,都返回 object
typeof Infinity  === 'number' // true
typeof function() {} === 'function' // true
複製代碼

typeof 可以判斷大多數類型,總結 typeof 的運算規則就是:spa

  • 對於基本類型,除了 null 之外均可以返回正確結果
  • 對於引用類型,除了 function 之外都返回 object
  • 對於 null,返回 object
  • 對於函數類型,返回 function

instanceof

instanceof 用來判斷 A 是不是 B 的實例,因此 instanceof 能夠正確地判斷對象的類型,由於其內部的實現機制是經過判斷對象的原型鏈中是否能找到類型的 prototypeprototype

[] instanceof Array // true
[].__proto__ === Array.prototype // true
複製代碼

也正是由於 instanceof 的實現本質上是基於原型鏈的查找,因此也會出現意料以外的狀況:code

[] instanceof Object // true
[].__proto__.__proto__ === Object.prototype // true
複製代碼

此外,instanceof 操做符的語法是 object instanceof constructor,要求操做符的左右兩側都必須是對象,因此沒法判斷 null, undefined 等類型。regexp

constructor

咱們知道當建立一個函數 F 時,JavaScript 引擎會爲 F 添加 prototype 屬性,而後在 prototype 屬性上添加一個 constructor 屬性,讓它指向 F 的引用:

function F() {}
F.prototype.constructor === F // true
複製代碼

這是引擎默認的行爲,目的是代表對象是由那個函數構造的,在 JavaScript 中,function 其實就是一個語法糖,全部的函數本質上都是一個 Function 對象。利用這一特性,咱們能夠經過 constructor 來判斷對象的數據類型,由於 JavaScript 爲咱們提供了不少的內置對象:

[].constructor === Array // true
''.constructor === String // true
false.constructor === Boolean // true
new Number().constructor === Number // true
複製代碼

可是 constructor判斷類型是 「不可靠的」,由於 constructor 屬性能夠被修改,好比:

var a = 1
a.constructor === Number // true
a.__proto__.constructor = String
a.constructor === Number // false
a.constructor === String // true
複製代碼

constructor 也不能用來判斷 nullundefined,由於他們都不是對象。

Object.prototype.toString.call

Object 原型上的方法 toString 返回一個表示該對象的字符串 [object Xxx]

ECMAScript 5 和隨後的 Errata 中定義,從 JavaScript 1.8.5 開始,toString() 調用 null 返回 [object Null]undefined 返回 [object Undefined]。對於 Object 對象,直接調用 toString 就能夠得到類型字符串,其餘類型,須要藉助 Object.prototype.toString.call/apply 來返回正確的類型值。至此,toString 成爲判斷數據類型最完備的一種方法:

Object.prototype.toString.call('') // [object String]
Object.prototype.toString.call(/([A-Z])\w+/g) // [object RegExp]
Object.prototype.toString.call(null) // [object Null]
Object.prototype.toString.call(undefined) // [object Undefined]
Object.prototype.toString.call(NaN) // [object Number]
複製代碼

咱們只須要對 toString 稍加封裝就能夠實現 JavaScript 中全部類型的判斷,舉個例子:

function getType(obj) {
  const typeClass = Object.prototype.toString.call(obj)
  const classMatch = {
    '[object String]': 'string',
    '[object Number]': 'number',
    '[object Boolean]': 'boolean',
    '[object Symbol]': 'symbol',
    '[object Object]': 'object',
    '[object Array]': 'array',
    '[object Function]': 'function',
    '[object RegExp]': 'regexp',
    '[object Date]': 'date',
    '[object Error]': 'error',
    '[object Window]': 'window',
    '[object HTMLDocument]': 'document'
  }
  if (obj == null) { // 若是是 null 或 undefined ,調用 toString 後返回
    return obj + ''
  } else { // 若是是 object 和 function ,調用 Object.prototype.toString 匹配具體的類型,其他狀況直接調用 typeof
    return (typeof obj === 'object' || typeof obj === 'function') ? classMatch[typeClass] : typeof obj
  }
}
複製代碼

相關推薦

勘誤與提問

若是有疑問或者發現錯誤,能夠在相應的 issues 進行提問或勘誤

若是喜歡或者有所啓發,歡迎 star,對做者也是一種鼓勵

(完)

相關文章
相關標籤/搜索