注:本文首發於個人博客,想得到更好的閱讀體驗,點我移步git
在最新的 ECMAScript規範 中,一共定義了 7 種數據類型,github
基本類型是存儲在 棧(Stack) 中的簡單數據段,引用類型的值是存儲在 堆(Heap) 中的對象。面試
數據類型的值存儲在堆中仍是棧中,取決於值的特性。基本類型佔據的空間固定,存儲在棧中按值訪問,能夠提高變量的查詢速度。引用類型的值大小不固定,不適合存儲在棧中,JavaScript中採起的作法是,將引用類型的值存儲在堆中,同時在棧中存儲值的訪問地址,因此引用類型是 按地址訪問 的。app
var arr = [1, 2, 3] // 引用類型的值其實就是存儲在堆內存中的對象,訪問方式爲按地址訪問,首先找到棧區中值的地址,而後沿着地址找到堆內存中對應的對象。
複製代碼
對於數據類型的判斷,JavaScript
也提供了不少種方法,遺憾的是,不一樣的方法獲得的結果良莠不齊,下面列出了我所知道的全部的類型判斷方法,若是有遺漏,歡迎在評論區補充。函數
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
instanceof
用來判斷 A 是不是 B 的實例,因此 instanceof
能夠正確地判斷對象的類型,由於其內部的實現機制是經過判斷對象的原型鏈中是否能找到類型的 prototype
。prototype
[] instanceof Array // true
[].__proto__ === Array.prototype // true
複製代碼
也正是由於 instanceof
的實現本質上是基於原型鏈的查找,因此也會出現意料以外的狀況:code
[] instanceof Object // true
[].__proto__.__proto__ === Object.prototype // true
複製代碼
此外,instanceof
操做符的語法是 object instanceof constructor
,要求操做符的左右兩側都必須是對象,因此沒法判斷 null
, undefined
等類型。regexp
咱們知道當建立一個函數 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
也不能用來判斷 null
和 undefined
,由於他們都不是對象。
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,對做者也是一種鼓勵
(完)